Dědičnost dnes

karel

Re:Dědičnost dnes
« Odpověď #60 kdy: 16. 01. 2017, 15:20:54 »
Většině diskutujících uniká je, že dědičnost v jazycích jako Java, C++ apod. representuje vlastně 3 koncepty. Je to dědění dat (většinou nechci, porušuje zapouzdření, lepší je použít skládání), dědění chování (většinou nechci, vede k fragile base class a porušuje zapouzdření), definice rozhraní(většinou chci, pomáhá k využití polymorfismu, pomáhá strukturovat kód - neprogramuju proti implementaci). Interface je dokonce často oddělen od dědičnosti - Java, C#.

3x chyba:
Jak porušuje dědění zapouzdření?!
Dědění chování potřebuju, abych jej nemusel vytvářet znovu.
Na definici rozhraní je rozhraní, k tomu třída neslouží!

No právě, pokud neslouží na definici rozhraní a nemá protected metody nebo proměnné, nemá cenu z ní dědit, můžu k ní přistupovat z venku. Pokud má protected metody nebo proměnné, můžu z potomka ovlivnit její chování, takže jsem rozbil zapouzdření předka.


Protože často ani "is a" neznamená, že je správné použít dědění ve smyslu dědění chování nebo dat a jde mi jen o interface.

??? Uveďte příklad.
Např. návrhový vzor Role https://en.wikipedia.org/wiki/Role_Class_Model Můžeš třeba definovat školní systém tak, že Je třída Osoba, z ní dědí Učitel a Student. Ze Studenta dědí BakalářskýStudent a MagisterskýStudent. Celý systém je podle pravidla "is a" správně. Jenom neumožňuje přechod z bakaláře na magistra nebo ze studenta na učitele. "is a" je podmínka nutná, ale ne dostačující.


n

Re:Dědičnost dnes
« Odpověď #61 kdy: 16. 01. 2017, 15:21:45 »
Každý asi zažil šílené hierarchie dědění, kde pomalu každá metoda volá nejdřív implementaci předka nebo kvanta protected atributů, co se ve většině tříd nikdy nepoužijí nebo se přes ně předávají argumenty funkce, ale ani jedno nejde rychle opravit bez rozbití poloviny systému.

To je běžným důsledkem nejen chybného použití dědění a skládání, ale taky chybným rozdělením funkcionalit mezi třídy a v důsledku chybným zapouzdřením a polymorfismem. Na to přesný návod neexistuje, to se prostě musí umět. Každopádně OOP za to nemůže.

...Napriklad pouzivani vyse zminenych protected pristupu tam, kde by byt nemely(skoro nikde). Kdyz davate neco protected, tak to je skoro stejne jako kdyby to bylo public...

To je samozřejmě nesmysl, právě protected dovoluje díky dědičnosti znovuvyužití hotové funkcionality v rámci zřetězení tříd bez nutnosti složitého delegování či opakování, na zapouzdření instance to pochopitelně vliv nemá.
Trochu jsem to prehnal se silou vyjadreni, ale: tim ze date neco protected, se zavazujete k udrzovani rozhrani stejne jako kdyby to byla public, pokud je dana trida deditelna. Pouze k temto metodam nema pristup primy klient tridy, ale ten ktery ji dedi. Nemuzete odstranovat protected metody ani menit jejich funkci(respektive muzete, ale rovna se to zmene rozhrani, pokud neni zabraneni dedeni.)

balki

Re:Dědičnost dnes
« Odpověď #62 kdy: 16. 01. 2017, 16:02:31 »
Vytrhavate veci z kontextu a reagujete mimo misu. Najprv si precitajte, o com som pisal a potom reagujte. Zda sa ze si musite doplnit znalosti.

"DRY objekt", som pouzil ako pejorativum. Take neexistuje, ale z kontextu je jasne hadam na co myslim.

Četl jsem vše od začátku. Asi mluvíme každý o něčem jiném. Odkazy k doplnění znalostí by mohly nedorozumění vyjasnit.

Tam, kde ste to vytrhli, som pisal o zneuzivani dedicnosti ako nastroja na odstranenie opakovania kodu.  Nepisal som nic o dedicnosti. Casting je v OOP jedna z moznosti vyuzitia polymorfizmu. Ako odkaz odporucam http://www.lmgtfy.com/?q=oop+casting

Karel (jiný)

Re:Dědičnost dnes
« Odpověď #63 kdy: 16. 01. 2017, 16:07:50 »
Dědičnost používám tam, kde se potřeba. Je nutné, aby byl splněn výrok "potomek" _je_ "rodič". Například Automobil je Vozidlo, Faktura je Doklad, Kvádr je Těleso apod. Zároveň musí být v programu možná zaměnitelnost potomka a rodiče. Pokud tato pravidla nejsou splněna, dědičnost nelze použít.

Tohle je v zásadě pravda, bohužel řada lidí nedočte k tomu "zároveň". Vidí "Faktura je Doklad" a jedou. Jenže ona i když faktura je doklad, tak spolu ve skutečnosti nemají nic společného. Příjemka je taky doklad. Stejně tak výdej materiálu do spotřeby nebo zálohová faktura. Ale nejsou zaměnitelné. Mají různé atributy, jiné metody a vlastně i jiné návaznosti (něco hýbá skladem, něco jen účetnictvím etc.) Program je pak beztak prolezlý "instanceof". Společný mají jen order type a order number. A to ještě ne konzistentně, takže pro některé typy dokladů je primárním klíčem tahle dvojice, ale pro jiné je primárním klíčem jen order number a pak pár, kde je součástí klíče i order suffix nebo order revision. Hlavně ale že je to OOP a že to v UML vypadá cool.

Prostě souhlasím s vámi, jen bych rád "možná zaměnitelnost potomka a rodiče" viděl v každé učebnici na prvním místě.

phpmág

Re:Dědičnost dnes
« Odpověď #64 kdy: 16. 01. 2017, 17:03:11 »
Jste nejlepší! Je to dobré téma a plno zajímavých pohledů.

Dědičnost používám tam, kde se potřeba. Je nutné, aby byl splněn výrok "potomek" _je_ "rodič". Například Automobil je Vozidlo, Faktura je Doklad, Kvádr je Těleso apod. Zároveň musí být v programu možná zaměnitelnost potomka a rodiče. Pokud tato pravidla nejsou splněna, dědičnost nelze použít.

Tohle je v zásadě pravda, bohužel řada lidí nedočte k tomu "zároveň". Vidí "Faktura je Doklad" a jedou. Jenže ona i když faktura je doklad, tak spolu ve skutečnosti nemají nic společného. Příjemka je taky doklad. Stejně tak výdej materiálu do spotřeby nebo zálohová faktura. Ale nejsou zaměnitelné. Mají různé atributy, jiné metody a vlastně i jiné návaznosti (něco hýbá skladem, něco jen účetnictvím etc.) Program je pak beztak prolezlý "instanceof". Společný mají jen order type a order number. A to ještě ne konzistentně, takže pro některé typy dokladů je primárním klíčem tahle dvojice, ale pro jiné je primárním klíčem jen order number a pak pár, kde je součástí klíče i order suffix nebo order revision. Hlavně ale že je to OOP a že to v UML vypadá cool.

Prostě souhlasím s vámi, jen bych rád "možná zaměnitelnost potomka a rodiče" viděl v každé učebnici na prvním místě.

A jak teda obecně řešit problém, kdy mám třeba 5 různých typů dat, které trochu spolu souvisí, ale dědičnost tam nejde použít přesně proto, co jsi napsal. 5 různých tříd nesdílejích nic? 5 různých služeb pracující s nimi? Nebo použít pro služby generickou službu? A co ukládání? Je to obecně složité téma, ale jen tak jestli máš nějaké tipy k tomu. Málo dat a hodně logiky je jednodušší, ale když jsou data, která je potřeba mít, tak se to komplikuje.


Re:Dědičnost dnes
« Odpověď #65 kdy: 16. 01. 2017, 18:03:59 »
Jeden ze základních problémů používání OOP je snaha pomocí dědičnosti (class hierarchy) modelovat realitu (nebo obecně doménu).

Ano, byla to jedna ze základních tezí vedoucí k propagaci a rozšíření OOP. Ale po třiceti (čtyřiceti?) letech si můžeme přiznat, že tohle naprosto selhalo.

čumil

Re:Dědičnost dnes
« Odpověď #66 kdy: 16. 01. 2017, 18:11:58 »
Jeden ze základních problémů používání OOP je snaha pomocí dědičnosti (class hierarchy) modelovat realitu (nebo obecně doménu).

Ano, byla to jedna ze základních tezí vedoucí k propagaci a rozšíření OOP. Ale po třiceti (čtyřiceti?) letech si můžeme přiznat, že tohle naprosto selhalo.
False.
OOP je o komunikačním grafu agentů.
Dědičnost je víceméně z nouze ctnost.
OOP prostě nejde ke statickému typování.

bob

Re:Dědičnost dnes
« Odpověď #67 kdy: 16. 01. 2017, 19:26:11 »
Např. návrhový vzor Role https://en.wikipedia.org/wiki/Role_Class_Model Můžeš třeba definovat školní systém tak, že Je třída Osoba, z ní dědí Učitel a Student. Ze Studenta dědí BakalářskýStudent a MagisterskýStudent. Celý systém je podle pravidla "is a" správně. Jenom neumožňuje přechod z bakaláře na magistra nebo ze studenta na učitele. "is a" je podmínka nutná, ale ne dostačující.

Jsi to spatne pochopil, na tom obrazku dole na te vazbe, je napsano "is a", ale neznamena to dedicnost, protoze ta se znaci v tom diagramu prazdnym trojuhelnickem. Praveze ta skola je modelovy priklad toho, ze se ma pouzit vazba "has a" a ne dedicnost.

Student nededi od cloveka. Cozpak je student vic clovekem nez delnik? Student ma smysl jen ve vztahu ke skole a ten vztah si nekdo vymyslel, je to pravni termin. Ty MAS VZTAH ("has a") vuci skole a tim je "student", "ucitel" atd... A muzes mit vic roli. Prave znamnka toho, ze by jsi potreboval roli zmenit nebo muzes mit vic roli (muzes byt ucitel i student i skolink zarovne? Muzes proc by ne.) je dalsi dobre voditko, proc to neni dedicnost.

Obecne plati, ze by jsi mel vzdycky delat co nejmene zavislosti. Literatura tomu rika loosely coupling, nicmene malokdo chape co tenhle buzz word znamena. Vazba "is a" je to nejsilnejsi co muze byt, kdyz  necim jsi, tak uz nemuzes byt  nicim jinym (ve svete trid). "has a",  casto implementovana jako promenna ve tride je mnohem volnejsi a kdekoliv si tak muzes rict, ze trida neco vlastni, tak je vzdy lepsi ji pouzit a kdyz si nejsem jistej, tak davam "has a".

Re:Dědičnost dnes
« Odpověď #68 kdy: 16. 01. 2017, 20:55:39 »
Připadá mi, že v této diskusi se míchá dědičnost jako koncept používaný při modelování reality v softwaru a dědičnost jako nástroj programovacího jazyka. A většina argumentace se implicitně točí kolem informačních systémů. Jenže OOP se používá i jinde. Např. GUI toolkity používají OOP již desítky let - namátkou Turbo Vision, Object Windows, GTK+, Qt. Dokonce k tomu nepotřebují ani OO jazyk (GTK+). V těchto aplikacích má použití dědičnosti s hlubokou polymorfní hierarchií hodně dobrý smysl. Naopak mi není moc jasné, proč se data v informačním systému snažit modelovat pomocí objektů a následně se hádat o různé aspekty OOP, když by lépe posloužil relační databázový model. Zvlášť, když data jsou už často v relační databázi uložena.

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Dědičnost dnes
« Odpověď #69 kdy: 16. 01. 2017, 21:22:17 »
...Napriklad pouzivani vyse zminenych protected pristupu tam, kde by byt nemely(skoro nikde). Kdyz davate neco protected, tak to je skoro stejne jako kdyby to bylo public...

To je samozřejmě nesmysl, právě protected dovoluje díky dědičnosti znovuvyužití hotové funkcionality v rámci zřetězení tříd bez nutnosti složitého delegování či opakování, na zapouzdření instance to pochopitelně vliv nemá.
A není to spíše naopak? Že protected umožňuje horkotěžko vyladěné chování rodičovské třídy nabourat a znepřehlední flow života instance, namísto jednoduchého, přímočarého a hlavně dobře otestovatelného delegování?

Protected je ekvivalent public. A jak tu bylo řečeno, nese si problém s tím, že se jedná o veřejné api, které je nutné dodržet. Což zvyšuje komplexitu.

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Dědičnost dnes
« Odpověď #70 kdy: 16. 01. 2017, 21:39:07 »
Za mě se domnívám, že dědičnost tak jak je implementována ve většině jazycích je na pytel.

Jako problém vidím hlavně to, že někteří tvrdí, že dědičnost slouží k tomu, abych znovupoužil existující funkcionalitu. I kdyby to byla pravda, tak je problém, že většina jazyků nedokáže oddělit znovupoužití chování, od definice vztahu mezi třídami. Jak tu SB popisoval, že Smaltalk má objekt, a ty ho vždycky přetěžuješ - to je sice hezký, ale s tím poděděným chováním si zároveň podědil i všechny ty vztahy. Což u typovaného jazyka může bejt dost problém. Další problém je v tom, že čím delší linie, tím méně se člověku chce opravovat chybné chování předka. Což je trapné.

Přijde mi mnohem šikovnější a čistější rozdělení v některých moderních jazycích. Jednak máš rozhraní/interface/class, a druhak máš trait/mixin. První slouží k určení vztahů, k vynucování požadavků na signaturu, etc. A to druhé slouží k reusable kódu. Výhoda je v tom, že mohu opravdu jen použít existující chování a přidat ho jinam.

A abych si trochu hejtnul: Za celou mou relativně dlouhou kariéru jsem si u dědičnosti vystačil s pravidlem, že potomek musí být specielní verzí předka. (Všimněte si, že tam není nic o chování.) A taky si všímám, že spousta kódu, se kterým přijdu do styku se u dědičnosti tímto pravidlem neřídí. Možná je to proto, že ta dědičnost je těžká, a vývojáři ji neumí používat, ale pak je to tedy koncept na prd, a neměl by se používat vůbec.

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Dědičnost dnes
« Odpověď #71 kdy: 16. 01. 2017, 21:47:25 »
Jste nejlepší! Je to dobré téma a plno zajímavých pohledů.

Dědičnost používám tam, kde se potřeba. Je nutné, aby byl splněn výrok "potomek" _je_ "rodič". Například Automobil je Vozidlo, Faktura je Doklad, Kvádr je Těleso apod. Zároveň musí být v programu možná zaměnitelnost potomka a rodiče. Pokud tato pravidla nejsou splněna, dědičnost nelze použít.

Tohle je v zásadě pravda, bohužel řada lidí nedočte k tomu "zároveň". Vidí "Faktura je Doklad" a jedou. Jenže ona i když faktura je doklad, tak spolu ve skutečnosti nemají nic společného. Příjemka je taky doklad. Stejně tak výdej materiálu do spotřeby nebo zálohová faktura. Ale nejsou zaměnitelné. Mají různé atributy, jiné metody a vlastně i jiné návaznosti (něco hýbá skladem, něco jen účetnictvím etc.) Program je pak beztak prolezlý "instanceof". Společný mají jen order type a order number. A to ještě ne konzistentně, takže pro některé typy dokladů je primárním klíčem tahle dvojice, ale pro jiné je primárním klíčem jen order number a pak pár, kde je součástí klíče i order suffix nebo order revision. Hlavně ale že je to OOP a že to v UML vypadá cool.

Prostě souhlasím s vámi, jen bych rád "možná zaměnitelnost potomka a rodiče" viděl v každé učebnici na prvním místě.

A jak teda obecně řešit problém, kdy mám třeba 5 různých typů dat, které trochu spolu souvisí, ale dědičnost tam nejde použít přesně proto, co jsi napsal. 5 různých tříd nesdílejích nic? 5 různých služeb pracující s nimi? Nebo použít pro služby generickou službu? A co ukládání? Je to obecně složité téma, ale jen tak jestli máš nějaké tipy k tomu. Málo dat a hodně logiky je jednodušší, ale když jsou data, která je potřeba mít, tak se to komplikuje.
Takové třídy můžou sdílet rozhraní. Nebo se dá udělat cluster tříd. Nakonec vždy záleží na jazyce, co dovolí použít. Např. v Go můžu udělat typový alias a přidat k němu metody. V některých jazycích to jde i bez aliasu. Ono těch možností je více a v každém jazyce je idiomatické něco jiného.

balki

Re:Dědičnost dnes
« Odpověď #72 kdy: 16. 01. 2017, 22:41:20 »
Přijde mi mnohem šikovnější a čistější rozdělení v některých moderních jazycích. Jednak máš rozhraní/interface/class, a druhak máš trait/mixin. První slouží k určení vztahů, k vynucování požadavků na signaturu, etc. A to druhé slouží k reusable kódu. Výhoda je v tom, že mohu opravdu jen použít existující chování a přidat ho jinam.

Traity su velmi sikovny koncept. Daju sa pomocou nich  "lepit objekty", podobne ako v subjektovo-orientovanom programovani. (Samozrejme, co do moznosti su slabsie ako SOP, ale aspon cast pokryvaju)  Javove som este neskusal, ale tie v scale boli velmi fajn.

anonym

Re:Dědičnost dnes
« Odpověď #73 kdy: 16. 01. 2017, 23:21:57 »
A abych si trochu hejtnul: Za celou mou relativně dlouhou kariéru jsem si u dědičnosti vystačil s pravidlem, že potomek musí být specielní verzí předka. (Všimněte si, že tam není nic o chování.) A taky si všímám, že spousta kódu, se kterým přijdu do styku se u dědičnosti tímto pravidlem neřídí. Možná je to proto, že ta dědičnost je těžká, a vývojáři ji neumí používat, ale pak je to tedy koncept na prd, a neměl by se používat vůbec.

Možná se tím neřídí proto, že se tím řídit nedá, protože to samotné pravidlo je blbost.

Příklad, kde tvou zmíněné pravidlo platí: je potřeba načítat data ze souboru, jeden řádek představuje vektor dat, ty se mají vložit do databáze. Musíš zpracovávat po dávkách, protože soubor může mít i několik gigabajtů. Každý soubor představuje jakoby jednu tabulku a tabulek existuje více, než jedna.

Budeš tedy 100% v kódu mít tuhle závislost:

Kód: [Vybrat]
TransactionRow dědí Row
AccountRow dědí Row

TransactionTable dědí Table
AccountTable dědí Table

Table agreguje Row

Platí zde pravidlo, že potomek musí být speciální verzí předka? Ano, platí. A je tenhle model správný? Jo, je.
(mimochodem tohle má na webu i Martin Fowler jako alternativu k ORM)


Pak budeš mít jinačí situaci. Chceš namodelovat situaci objektů kolem nás, třeba proto, že je v palikaci budeš chtít vykreslovat v nějaké interaktivní hře. Takže řekněme, že zrovna děláš nádoby.

Kód: [Vybrat]
Hrnek dědí Nádoba
Sklenice dědí Nádoba

Voda dědí Náplň
Hrách dědí Náplň

Nádoba agreguje Náplň

Platí zde pravidlo, že potomek musí být speciální verzí předka? Ano, platí. A je tenhle návrh ok? Ne, je úplně na piču. A přitom kde je problém? Vždyť je to v podstatě úplně to samé, jako příklad Table - Row.

Rozdíl je akorát v tom, že když se snažíme svět kolem nás napasovat do OOP, tak to vždycky dopadne špatně. Přitom zrovna na reálném světě se OOP vysvětluje na těchto hloupých případech. Třeba že Auto má Kola a Dveře. Kdybychom to chtěli potom i takhle implementovat, protože děláme třeba hru, tak je to snad ten největší antipatern.

Tak jak je možné, že v jedné situaci je jedna a ta samá věc ok a v jinačí je úplně špatně, a jakto že to jde tak dobře poznat zrovna na příkladě, modelujeme-li relativně jasně zadaný úkon v rámci PC světa a dáme úplně v principu to samé do kontrastu s reálným světem?

Je to proto, protože reálný svět je velice složitý a kdyby se chtěl namodelovat, tak by vyšlo, že všechno dědí všechno, všechno agreguje všechno a závislosti v něm jdou těžko postihnout a ikdyby šly, vychází vícejaké možnosti jak něco namodelovat, a proč? Protože OOP je úplně napiču pokud jde o modelování reálného světa, je to jen paradigma v rámci malého světa počítačů.

Přitom, soubor na disku je rovněž reálná věc.

Z toho plyne malá úprava: OOP se má používat zcela účelově a má sloužit při zpřehlednění aplikace. Neplatí žádné pravidla typu "potomek musí být speciální verzí předka", platí jenom jedno pravidlo, "musí to být účelné a dávat to to smysl v závislosti na tom, co budeme dělat" a to i v případě, kdy se chce někdo vyhnout duplicitě v kódu.

Můj názor.






anonym

Re:Dědičnost dnes
« Odpověď #74 kdy: 16. 01. 2017, 23:24:29 »
Zelenáč, prorok a junior Java programátor, léta páně 2017