Mi a kovariancia és az ellentmondás a programozásban? – CloudSavvy IT

Avatar Gadam | 2021.03.02.

[ad_1]

Absztrakt kép mutatja a táguló sárga téglalapokat

A kovariancia és az ellentmondás olyan kifejezések, amelyek leírják, hogy egy programozási nyelv hogyan kezeli az altípusokat. A típus varianciája meghatározza, hogy az altípusai felcserélhetők-e vele.

A variancia egy átláthatatlannak tűnő koncepció, amíg konkrét példát nem kapunk. Vegyünk egy alaptípust Animal altípusával Dog.

interface Animal {
    public function walk() : void;
}
 
interface Dog extends Animal {
    public function bark() : void;
}

Minden „állat” járhat, de csak a „kutya” ugathat. Vizsgáljuk meg, mi történik, ha ezt az objektumhierarchiát alkalmazzuk az alkalmazásunkban.

Felületek összekötése együtt

Mivel minden Animal tud járni, létrehozhatunk egy általános felületet, amely bármelyiket gyakorolja Animal.

interface AnimalController {
 
    public function exercise(Animal $Animal) : void;
 
}

A AnimalController van egy exercise() metódus, amely tipizálja a Animal felület.

interface DogRepository {
 
    public function getById(int $id) : Dog;
 
}

Most van egy DogRepository olyan módszerrel, amely garantáltan visszaadja a Dog.

Mi történik, ha megpróbáljuk ezt az értéket a AnimalController?

$AnimalController -> exercise($DogRepository -> getById(1));

Ez megengedett azokon a nyelveken, ahol a kovariáns paraméterek támogatottak. AnimalController meg kell kapnia egy Animal. Amit elhaladunk, az valójában a Dog, de mégis kielégíti a Animal szerződés.

Ez a fajta kapcsolat különösen fontos, ha osztályokat hosszabbítasz. Lehet, hogy általánosat akarunk AnimalRepository amely minden állatot visszakeres a faj részletei nélkül.

interface AnimalRepository {
 
    public function getById(int $id) : Animal;
 
}
 
interface DogRepository extends AnimalRepository {
 
    public function getById(int $id) : Dog;
 
}

DogRepository módosítja a AnimalRepository—Amint a hívók megkapják a Dog an helyett Animal—De alapvetően nem változtat rajta. Pontosabban szól a visszatérési típusáról. A Dog még mindig egy Animal. A típusok kovariánsak, tehát DogRepositorymeghatározása elfogadható.

A kontraverziót nézve

Vizsgáljuk meg most az inverz példát. Kívánatos lehet, hogy legyen egy DogController, ami megváltoztatja a „Kutyák” gyakorlásának módját. Logikailag ez még kiterjesztheti a AnimalController felület. A gyakorlatban azonban a legtöbb nyelv nem engedi felülírni exercise() a szükséges módon.

interface AnimalController {
 
    public function exercise(Animal $Animal) : void;
 
}
 
interface DogController extends AnimalController {
 
    public function exercise(Dog $Dog) : void;
 
}

Ebben a példában DogController meghatározta exercise() csak a Dog. Ez ütközik a AnimalController, amely lehetővé teszi bármely „állat” áthaladását. A szerződés teljesítése érdekében DogController ezért el kell fogadnia bármelyiket Animal.

Első pillantásra ez zavarónak és haszontalannak tűnhet. A korlátozás mögött álló érvelés világosabbá válik, amikor gépel AnimalController:

function exerciseAnimal(
    AnimalController $AnimalController,
    AnimalRepository $AnimalRepository,
    int $id) : void {
 
    $AnimalController -> exercise($AnimalRepository -> getById($id));
}

Az a probléma AnimalController lehet egy AnimalController vagy a DogController– a mi módszerünk nem azt jelenti, hogy melyik interfész-megvalósítást használja. Ez ugyanazokra a kovariancia szabályokra vezethető vissza, amelyek korábban hasznosak voltak.

Mint AnimalController esetleg legyen a DogController, most egy komoly futásidejű hiba vár felfedezésre. AnimalRepository mindig ad vissza egy Animal, Tehát, ha $AnimalController van a DogController, az alkalmazás össze fog esni. A Animal típus túl homályos ahhoz, hogy átadja a DogController exercise() módszer.

Érdemes megjegyezni, hogy a módszerek túlterhelését támogató nyelvek elfogadják DogController. A túlterhelés lehetővé teszi több azonos nevű metódus definiálását, feltéve, hogy eltérőek aláírások (Különböző paraméter- és / vagy visszatérési típusaik vannak.). DogController lenne egy extrája exercise() módszer, amely csak a „Kutyákat” fogadta el. Ugyanakkor meg kell valósítania az upstream aláírást is, elfogadva minden „állatot”.

A variancia kérdések kezelése

A fentieket úgy lehet összefoglalni, hogy a függvény visszatérési típusai megengedettek kovariáns, míg az argumentumtípusok legyenek ellentmondásos. Ez azt jelenti, hogy egy függvény egy specifikusabb típust adhat vissza, mint amit az interfész meghatároz. Elfogadhat egy elvontabb típust is argumentumként (bár a legnépszerűbb programozási nyelvek ezt nem valósítják meg).

Leggyakrabban akkor fordul elő varianciaproblémákkal, amikor generikusokkal és gyűjteményekkel dolgozik. Ezekben a forgatókönyvekben gyakran szeretne AnimalCollection és a DogCollection. Kellene DogCollection kiterjeszt AnimalCollection?

Így nézhetnek ki ezek az interfészek:

interface AnimalCollection {
    public function add(Animal $a) : void;
    public function getById(int $id) : Animal;
}
 
interface DogCollection extends AnimalCollection {
    public function add(Dog $d) : void;
    public function getById(int $id) : Dog;
}

Először nézi getById(), Dog altípusa Animal. A típusok kovariánsak, és a kovariáns visszatérési típusok megengedettek. Ez elfogadható. Újra megfigyeljük a variancia kérdését add() bár-DogCollection meg kell engednie bármelyiket Animal hozzá kell adni a AnimalCollection szerződés.

Ezt a kérdést általában úgy lehet megoldani, hogy a gyűjtemények megváltoztathatatlanná válnak. Csak új elemek hozzáadását engedélyezze a gyűjtemény konstruktorában. Ezután megszüntetheti a add() módszer teljesen, így AnimalCollection érvényes jelölt erre DogCollection örökölni.

A variancia egyéb formái

A kovariancia és az ellentmondás mellett a következő feltételekkel is találkozhat:

  • Bivariant: A típusrendszer akkor változatos, ha a kovariancia és az ellentmondás egyaránt érvényes egy típusú kapcsolatra. A változatosságot a TypeScript az előtte használta TypeScript 2.6
  • Változat: A típusok akkor változatosak, ha kovariancia vagy ellentmondás érvényesül.
  • Állandó: Bármely típus, amely nem variáns.

Általában kovariáns vagy kontraverziós típusokkal fog dolgozni. Az osztály öröklődését tekintve a B típus kovariáns az A típussal, ha igen kiterjed A. A B típus ellentmond az A típusnak, ha B őse.

Következtetés

A variancia egy olyan fogalom, amely elmagyarázza a típusrendszereken belüli korlátokat. Általában csak arra kell emlékeznie, hogy a kovariancia elfogadott a visszatérési típusokban, míg a paramétereknél az ellentmondást alkalmazzák.

A variancia szabályai a Liskov helyettesítési elv. Ez azt állítja, hogy képesnek kell lennie arra, hogy egy osztály példányait alosztályainak példányaival helyettesítse anélkül, hogy megváltoztatná a tágabb rendszer tulajdonságait. Ez azt jelenti, hogy ha a B típus kiterjeszti az A típust, akkor a A helyettesíthetők a B.

A fenti példánk használata azt jelenti, hogy képesnek kell lennünk a helyettesítésre Animal val vel Dog, vagy AnimalController val vel DogController. Itt újra látjuk, miért DogController nem írhatja felül exercise() hogy csak Kutyákat fogadjak el – már nem tudnánk helyettesíteni AnimalController val vel DogController, mivel a fogyasztók jelenleg elhaladnak egy Animal most meg kellene adnia a Dog helyette. A kovariancia és az ellentmondás érvényesíti az LSP-t és biztosítja a konzisztens viselkedési normákat.

[ad_2]
Source link


Written by Gadam