OOP - dědičnost a sdílení kódu rubrika: Programování: PHP

12 Kit
položil/-a 26.10.2015
 
upravil/-a 26.10.2015

V v jedné z diskuzí http://devel.cz/otazka/struktura-vyjimek#answer-22346 jsem se dozvěděl, že

... problém s nadužíváním dědičnosti je v tom, že se používá pro sdílení kódu, což je obrovská chyba.

S tímto výrokem nesouhlasím a ptám se: Proč je sdílení kódu v rodičovské třídě chybou? Co je myšleno tím "sdílením kódu"? Sdílím kód nebo nesdílím, pokud mám všechny atributy "private"? Používání traits je nebo není považováno za sdílení kódu? Co třeba include()/require()? Je to nebo není sdílení kódu? Je to nebo není obrovskou chybou?

Dotaz jsem zařadil do kategorie PHP, protože mě zajímají hlavně odpovědi týkající se specifik tohoto jazyka, ale nebráním se ani jiným pohledům.

Příklady dědičností, které běžně používám:

class UserView extends View { ... }
class LoginView extends View { ... }
class LoginController extends Controller { ... }
class ErrorView extends View { ... }
class HttpException extends Exception {}

Komentáře

  • Tomáš Votruba : Hodil bys nějaký use case? Rád bych se k tomu věcně vyjádřil a hodila by se specifikace na konkrétní případ. 26.10.2015
odkaz
6 kohven
odpověděl/-a 26.10.2015

Ono je to možná jen nešťastně formulováno. O sdílení kódu jde i v případě, kdy je dědičnost namístě. Ale chápu to tak, že je potřeba si dát pozor, aby se dědičností nenahrazovala kompozice. Někdy je výhodnější zpracovávat objekty různých tříd se stejným rozhraním jednou funkčností, než sdílet jednu funkčnost skrz jednoho předka.

Komentáře

  • Kit : Pokud různé třídy mají mít jednu funkčnost, tak se to dá udělat implementací společného rozhraní, ale nedá se tak sdílet společná funkčnost. Pokud není porušen LSP, tak vážně nevidím důvod vyhýbat se dědičnosti, viz mé příklady. 26.10.2015
  • Taco : Další problém je v tom, že takových god objektů se hrozně blbě zbavuje. 26.10.2015
  • Taco : @kohven: Zkusím ještě jednu formulaci. Při programování chcem vytvořit objekt, který má nějaké chování. Někdy je žádoucí dědit, protože chcem aby to byl potomek toho objektu. Chcem aby se chovat stejně, nebo podobně. Aby se dal nějakým konkrétním způsobem použít. Nebo dokonce chcem, aby při změně předka zohlednil tyto změny i potomek. Toto je cílem. Zda k tomu použijem dědění, nebo kompozici je věc, kterou vývojář zvažuje. Zásadní problém vidím v tom, když to vývojář otočí, a začne dědění používat za účelem recyklace kódu. To je obrovská chyba. Kód je naprosto druhořadá záležitost. 26.10.2015
  • Kit : @Taco: Otázkou je, co je a co není "god object". Co třeba třída Exception? Sdílení kódu téměř všemi potomky jak vyšité. Je to god object? 26.10.2015
  • Taco : @Kit: Tak god object je něco jiného, že jo. Každopádně všechny výjimky přímo nebo nepřímo dědí z třídy Exception, protože všechny výjimky jsou výjimkami a mají se chovat jako výjimky. 26.10.2015
  • Kit : @Taco: "všechny výjimky jsou výjimkami a mají se chovat jako výjimky". To je přesně to, co tvrdím ve svých příkladech, viz výše. UserView je View a má se chovat jako View. Je to příklad správně použité dědičnosti. Tohle je ten důvod, proč mi vadí výroky typu: "nepoužívejte dědičnost, všechny třídy pište final", viz Marco Pivetta. 26.10.2015
  • Taco : @Kit: No a co já s tim jako? 26.10.2015
  • Kit : @Taco: Takové třídy obvykle sdílejí prostřednictvím rodičovské třídy značnou část kódu, což jsi označil za obrovskou chybu. 26.10.2015
  • Taco : @Kit: Kde jsem uvedl takovou formulaci? 26.10.2015
  • Kit : @Taco: http://devel.cz/otazka/struktura-vyjimek#answer-22346 v 11:55 26.10.2015
  • Taco : @Kit: Nikde nevidím, že bych psal, že to, že třídy sdílejí značnou část kódu je chyba. 26.10.2015
  • Kit : cite: "Protože problém s nadužíváním dědičnosti je v tom, že se používá pro sdílení kódu, což je obrovská chyba." 26.10.2015
  • Taco : @Kit: Ano, to jsem psal, a za tím si stojím. Jenže to jaksi není to co ty tvrdíš, že tvrdím, že jo. 26.10.2015
  • Kit : @Taco: Tak jsme si to konečně vyjasnili a můžeme jít v klidu od toho. 26.10.2015
  • vojta.tranta : Jsou jazyky, kde existuje několikanásobná dědičnost (plnohodnotná, narozdíl od PHP traitů) a tam se tohle neděje, prostě se udělá mixin a nazdar. Navíc se dají dvě třídy spojit. Spousta lidí to hejtuje a ano, dělá to guláš v kódu, pokud se to používá blbě (to platí ale o všem), na druhou stranu to řeší spoustu problému klasického "javovského" OOP, která bývá nepružné (dopředu hádáš vývoj aplikace v budoucnosti a nemůžeš se nikdy trefit). Můžeš zkusit javascript nebo python, které tohle umí, je to minimálně zajímavá zkušenost. 29.10.2015
  • Taco : @vojta.tranta: Javascript a Python mají zase své problémy. A taky nejsou pro každého. Mě třeba statické typování děsně schází. Přijde mi, že to bez toho tak nějak nedrží pohromadě. 30.10.2015
  • error414_1 : No ukazkove chybne pouziti dedicnosti je v androidu a jejich Activity. 30.10.2015
  • Anonym : @Taco V Pythonu existují anotace a od nové verze jsou nově propojeny/rozšířeny s modulem `typing` -- takže to můžeš prohnat nějakým analyzátorem. Vícenásobná dědičnost je v Pythonu vlastně jednoduchá. Např. pokud dvě třídy deklarují stejnou metodu ... vezme se ta první v seznamu tříd od kterých se dědí. 30.10.2015
  • Anonym : @vojta.tranta taková kouzla jsou dobrá ne v ručně psaném kódu ale v nějakém generátoru kódu -- metaprogramu, pak je to vlastnost jazyka, která je hrozně mocná. 30.10.2015
  • Anonym : @Kit V téhle odpovědi to je dobře napsané: Pokud máš třídu, od které dědíš napříč různými logickými sekcemi programu (moduly, balíčky), protože teď zrovna sdílejí stejnou funkcionalitu (metodu), pak si zaděláváš na průser. Nevím jestli to je vlastně nutně otázka dědičnost vs kompozice. 30.10.2015
  • Kit : @uetoyo: Jde nejspíš o to, že mnoho programátorů začalo nadužívat dědičnost. Sám jsem si to v minulosti vyzkoušel a zjistil jsem, že tyto "god objects" vedou do pekel. Pak přišel jiný programátor a řekl zkratkovitě: Nepoužívejte dědičnost, je to cesta do pekel. A další si ještě přisadil: Dědičnost není potřebná, všechny třídy pište final. Přitom dědičnost v programování má svůj význam - jen se musí používat s rozumem. 30.10.2015
  • Taco : @uetoyo: Díky za tip na typing. Vyzkouším si to. Jak si to poradí s duck-typinge? (Poradí myslím, zbavit, vyhodit, odstranit.) 30.10.2015
  • Anonym : @Taco ... promiň za pozdní reakci ... popravdě nejsem v tom ještě taky doma. Ještě tak trochu okukuju a čekám kam se to posune. Mne to zatím jen pomáhá v orientaci v kódu -- přeci jen lidi Python používají právě díky tomu, že se toho nemusí tolik psát -- anotace `some_var: List[List[str]]` není zdaleka pěkná. 9.11.2015
  • Taco : @uetoyo: No, já Python nesnáším proto, že sice nemusím moc psát, ale taky mi vůbec, ale vůbec nepomáhá [když udělám chybu]. Proto informaci, že Rossum zvažuje do Python přidat volitelné typy-hinty mi přišla jako 1/ Rossum se definitivně zbláznil; 2/ Hurrá, typy. 9.11.2015
  • Anonym : @Taco ... no jo, já taky nemám Python rád (ale pořád je to flexibilní jazyk oproti např. PHP)-- add Rossum: Kdo by chtěl po 20 letech přiznat že to měl být raději OCaml (moje kamrádka při několikátém pokusu o instalaci knihovny ... přečti `cha.py` několikrát rychle za sebou .) 10.11.2015

Pro zobrazení všech 5 odpovědí se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.