Liskov substitution principle

Üdvözlöm, Ön a Liskov substitution principle szó jelentését keresi. A DICTIOUS-ban nem csak a Liskov substitution principle szó összes szótári jelentését megtalálod, hanem megismerheted az etimológiáját, a jellemzőit és azt is, hogyan kell a Liskov substitution principle szót egyes és többes számban mondani. Minden, amit a Liskov substitution principle szóról tudni kell, itt található. A Liskov substitution principle szó meghatározása segít abban, hogy pontosabban és helyesebben fogalmazz, amikor beszélsz vagy írsz. ALiskov substitution principle és más szavak definíciójának ismerete gazdagítja a szókincsedet, és több és jobb nyelvi forráshoz juttat.

Főnév

Liskov substitution principle (tsz. Liskov substitution principles)

  1. (informatika) A Liskov-helyettesítési elv az objektum-orientált tervezés egyik alapelve. Nevét Barbara Liskov után kapta, aki 1987-ben Jeannette Winggel közösen publikálta az elvet.

Az elv a következő formális megfogalmazásban hangzik el:

„Ha S típus származik T típusból, akkor minden olyan helyen, ahol T típust használnánk, S típust is használhatunk anélkül, hogy a program helyes működését befolyásolná.”

Másképpen mondva: Ha egy kód egy bázisosztály (T) példányával helyesen működik, akkor az leszármazott osztályok (S) példányaival is helyesen kell működnie — anélkül, hogy a kódot módosítani kellene.



📚 Alapötlet

Az OOP egyik fő előnye a polimorfizmus: készíthetünk olyan kódot, amely bázisosztályokra íródik, de a konkrét példányok lehetnek leszármazott osztályok példányai is.

Az LSP azt mondja ki, hogy ennek a polimorfizmusnak „átlátszóan” kell működnie: ha lecserélek egy T-t egy S-re, a program viselkedése nem válhat hibássá vagy értelmét vesztetté.



🎨 Szemléletes példa

1️⃣ Jó példa — betartott LSP

class Bird {
public:
    virtual void fly() {
        std::cout << "Flying..." << std::endl;
    }
};

class Sparrow : public Bird {
public:
    void fly() override {
        std::cout << "Sparrow flying..." << std::endl;
    }
};

Itt Bird osztályt használhatok bármilyen Bird-ként viselkedő objektummal. Ha a függvény Bird*-ot vár, és kap egy Sparrow*-t, helyesen fog működni.

void makeBirdFly(Bird* b) {
    b->fly();
}

LSP nem sérül.



2️⃣ Rossz példa — LSP sérülése

class Bird {
public:
    virtual void fly() {
        std::cout << "Flying..." << std::endl;
    }
};

class Penguin : public Bird {
public:
    void fly() override {
        throw std::runtime_error("Penguins can't fly!");
    }
};

Ha most egy makeBirdFly() függvény Bird*-ot vár, és kap egy Penguin*-t:

Bird* bird = new Penguin();
makeBirdFly(bird); // program kivételt dob

Ez már sérti az LSP-t: a Penguin nem viselkedik helyettesítőként a Bird helyett, mivel nem tud “repülni”.

👉 Ilyenkor a tervezés hibás — talán nem is kéne a Penguin-t Bird-ből származtatni, vagy az fly() metódus nem minden Bird számára értelmes.



📏 Hivatalos definíció — Liskov & Wing (1987)

A leszármazott típus viselkedése nem sértheti a bázistípus által elvárt invariánsokat.

Konkrétan:

  1. Prekondíciókat nem szabad erősíteni. (Nem követelhetek többet egy metódus meghívásához.)
  2. Posztkondíciókat nem szabad gyengíteni. (Nem adhatok kevesebb eredményt vagy gyengébb garanciát.)
  3. Invariánsokat meg kell tartani. (Az objektum állapotát jellemző tulajdonságok érvényesek maradnak.)



🔍 LSP a SOLID elvekben

Az LSP a híres SOLID elvsorozat L betűje:

  • S — Single responsibility principle
  • O — Open/closed principle
  • L — Liskov substitution principle
  • I — Interface segregation principle
  • D — Dependency inversion principle

A SOLID elvek célja: robosztus, jól tervezett, könnyen bővíthető OOP rendszerek készítése. Az LSP biztosítja, hogy a polimorfizmus megbízható legyen.



⚠️ Tipikus LSP-sértések

  • Túl általános bázisosztály, nem minden leszármazott tudja értelmesen megvalósítani.
  • Olyan absztrakt metódusokat definiálunk, amelyek egyes leszármazottak számára nem értelmesek (mint a “fly” a pingvinnél).
  • Nem követjük a bázisosztály által meghatározott szerződést (contract).



🧰 Hogyan tartsuk be?

  • Használjunk tiszta absztrakciót: csak azt tegyük a bázisosztályba, ami minden leszármazottra igaz.
  • Kerüljük a „hamis” öröklődést: ha az öröklés inkább implementáció-újrafelhasználást szolgál, ne származtassunk, hanem kompozíciót használjunk.
  • Következetes viselkedést tartsunk fenn: leszármazott metódusok ne vezessenek váratlan kivételhez, extra követelményekhez, vagy hiányos viselkedéshez.



🏆 Összefoglalás

Liskov substitution principle (LSP)
Minden leszármazott osztály helyettesíthető legyen a bázisosztályával.
Ne sértsük meg az elvárt szerződést.
Prekondíciókat ne erősítsünk.
Posztkondíciókat ne gyengítsünk.
Invariánsokat tartsuk meg.
Ha LSP sérül, a kód törékeny, nehezen karbantartható lesz.