Při výuce objektově orientovaného programování a po zvládnutí základů objektů, polí a metod strávíme většinu času dědičností. Dědičnost znamená, že přebíráme určitou část implementace ze základní třídy. Stačí vytvořit podtřídu základní třídy, abyste zdědili každé nesoukromé pole a metodu.
Auto a letadlo jsou dopravní prostředky, takže je zřejmé, že obě tyto třídy by měly být rozšířeny ze společné základní třídy Vehicle. To je typický akademický příklad, ale při rozhodování o provázání těchto tříd vztahem dědičnosti bychom si měli uvědomit některé důsledky.
Obr. 1 Implementace vztahu dědičnosti.
V tomto případě jsou třídy navzájem úzce propojeny - to znamená, že změny chování každé třídy lze dosáhnout provedením změn v základní třídě. kód. To může být výhoda i nevýhoda - záleží na tom, jaké chování očekáváme. Pokud je dědičnost použita v nesprávný okamžik, může se proces přidávání nové funkce setkat s implementačními potížemi, protože nebude odpovídat vytvořenému modelu třídy. Budeme si muset vybrat mezi duplikováním kódu a reorganizací našeho modelu - a to může být opravdu časově náročný proces. Kód, který provádí vztah dědičnosti, můžeme označit jako "otevřený-uzavřený" - to znamená, že je otevřený pro rozšíření, ale uzavřený pro modifikaci. Za předpokladu, že ve třídě Vozidlo existuje obecná, definovaná operace motoru, každého vozidla, v okamžiku, kdy bychom chtěli do hierarchie tříd přidat model bezmotorového vozidla (např. motorky), museli bychom v našich třídách provést závažné změny.
třída Vozidlo
def start_engine
end
def stop_engine
end
end
třída Plane < Vehicle
def move
start_engine
...
stop_engine
end
konec
Složení
Pokud nás zajímá pouze část chování existující třídy, je dobrou alternativou k dědičnosti použití kompozice. Místo vytváření podtříd, které dědí veškeré chování (ty, které potřebujeme, i ty, které vůbec nepotřebujeme), můžeme izolovat funkce, které potřebujeme, a vybavit naše objekty odkazy na ně. Tímto způsobem se vzdáme myšlenky, že objekt je typ základní objekt, ve prospěch tvrzení, že obsahuje pouze některé části jeho vlastností.
Obr. 2 Použití složení
Tímto přístupem můžeme izolovat kód, který je zodpovědný za provoz motoru, do autonomní třídy s názvem Engine a umístit odkaz na ni pouze do tříd, které představují vozidla s motorem. Izolování funkcí pomocí kompozice zjednoduší strukturu třídy Vozidlo a posílí zapouzdření jednotlivých tříd. Nyní mohou vozidla působit na motor pouze tak, že použijí jeho veřejné rozhraní, protože již nebudou mít informace o jeho implementaci. Navíc to umožní používat různé typy motorů v různých vozidlech, a dokonce umožní jejich výměnu za běhu programu. Použití kompozice samozřejmě není bezchybné - vytváříme volně propojenou množinu tříd, kterou lze snadno rozšiřovat a která je otevřená modifikacím. Zároveň je však každá třída propojena s mnoha dalšími třídami a musí mít informace o jejich rozhraních.
třída Vozidlo
konec
třída Motor
def start
end
def stop
end
end
class Plane < Vehicle
def inicializovat
@engine = Engine.new
end
def move
@engine.start
@engine.stop
end
def change_engine(new_engine)
@engine = new_engine
end
end
Volba
Oba popsané přístupy mají své výhody i nevýhody, jak si tedy mezi nimi vybrat? Dědičnost je specializace, takže je nejlepší je použít pouze pro problémy, ve kterých existují typové vztahy "is-a" - máme tedy co do činění se skutečnou hierarchií typů. Protože dědičnost těsně spojuje třídy dohromady, měli bychom v první řadě vždy zvážit, zda použít kompozici, nebo ne. Kompozici bychom měli použít u problémů, v nichž existují typové vztahy "má-a" - třída má tedy mnoho částí, ale je něčím víc než množinou tříd. Letadlo se skládá z částí, ale samo o sobě je něčím víc - má další schopnosti, například let. Půjdeme-li s tímto příkladem dále, mohou se jednotlivé části vyskytovat v různých specializovaných variantách, a pak je vhodný okamžik pro použití dědičnosti.
Dědičnost i kompozice jsou pouze nástroje, které mají programátoři k dispozici, takže výběr správného nástroje pro konkrétní problém vyžaduje zkušenosti. Pojďme tedy trénovat a učit se z vlastních chyb 🙂