313
« kdy: 20. 01. 2017, 16:53:19 »
Celý problém, který jsem naschvál jen nakousnul a nedořek, je v tomto:
Dědičnost NENÍ vhodná na modelování každého vztahu A is B. Pouze vztahu A is B a A je záměnné pro B. Což v podstatě znamená and A is B a navíc A umí vše co B. Což u čtverce ve vztahu k obdélníku není pravda - a proto modelace čtverce jako speciálního případu obdélníka je někdy špatně.
A naopak - v určitém kontextu se může hodit to, co jsem provokativně nadhodil: pokud budu řešit např. problém optimalizace vyplnění prostoru pomocí dlaždic, tak se mi může hodit nadefinovat čtvercovou dlaždici, která má (mimo pozice) jeden parametr volnosti, a z ní potomka obdélníkovou dlaždici, která má jeden parametr navíc: poměr stran.
Oba tyto vztahy: Čtverec je podmnožinou obdélníka i obdélník je podmnožinou čtverce splňují pouze jednu z výše uvedených podmínek pro správnou dědičnost: obdélník není čtverec, ale čtverec neumí vše, co obdélník. Proto pro obě tyto dědičnosti najdete protipříklady, kdy jejich užití selže.
A to jsem neještě nemluvil o kosočtvercích a kosodélnících: je čtverec speciální případ kosočtverce (fixuje úhel) nebo kosodélníku atd..., atd....
Osobně v praxi používám to, že pro dědění rozhraní, které jsou více o tom, co předmět umí než co předmět je, volím dědění dle "umí", tedy rozhraní obdélníku bych třeba navrhl jako speciální případ k rozhraní čtverce. Naopak u dědičnosti je dobré zachovávat především vztah "is a", ovšem s tím, že pokud bych porušil (používaný) vztah "umím", tak nedědit.
Celé je to způsobeno tím, že dědičnost i rozhraní je jen velké zjednodušení reality. Které lze použít jen potud, pokud to zjednodušení není na úkor porušení vztahů, které je třeba kódem zachytit. Proto někdy je bez problémů popsat čtverec jako obdélník, někdy ne.
PS: Jinak Kiwi má částečně dobrý postřeh s tím, že výše uvedené problémy se zhoršují mutabilitou objektů. Ovšem i bez mutability to je problém: pokud mám třídy A který může mít stav X, a jejího potomka B, který v stavu X být nemůže, tak prostě to je problém, který mi immutabilita nijak neřeší. Protože správná reakce na žádost vrať mi B ve stavu X není z B nejprve udělat A, správná odpověď je říci: já v tom stavu být nemohu.
Jde to vyřešit tím, pokud součástí "protokolu" třídy A je "nastavení do stavu X se nemusí povést". Pak vlastně není problém. Naopak pokud je součástí byť implicitní definice třídy, že přechod do stavu X lze vždy, tak vlastně z definice vidíme, že B nemůže být potomkem A - tedy že čtverec není obdélník.
Z tohoto pohledu by to vlastně immutabilita řešila, akorát třída A by neměla mít metodu: vrať mi sebe ve stavu X, ale vrať mi objekt A, který vznikne ze mě převedením do stavu X. Tedy obdélník i čtverec by měli metodu: vrať_kopii_obdélníku_se_stranou_B. To ovšem není řešením tohoto problému jako celého, pořád je tu problém v "odstraňování schopností", např: Člověk umí běžet. Chromý člověk je člověk, ale běžet neumí.