GRASP – 4 – Polymorphism, Pure fabrication a Indirection

V tomto díle o návrhových principech GRASP (General Responsibility Assignment Software Patterns) projdeme principy Polymorphism, Pure fabrication a Indirection, které se zabývají strukturními prvky architektury.

Seriál: Principy objektově orientovaného návrhu (12 dílů)

  1. Návrhové principy: SOLID 9.5.2012
  2. Návrhové principy: Deméteřin zákon 18.5.2012
  3. Návrhové principy: DRY 30.5.2012
  4. GRASP – 1 – Úvod a Protected variations 20.6.2012
  5. GRASP – 2 – High cohesion 2.7.2012
  6. GRASP – 3 – Low coupling 16.7.2012
  7. GRASP – 4 – Polymorphism, Pure fabrication a Indirection 30.7.2012
  8. GRASP – 5 – Information expert a Creator 15.8.2012
  9. GRASP – 6 – Controller a jak GRASP používat 17.9.2012
  10. GRASP – 7– Modelové příklady 15.10.2012
  11. Návrhové principy: Tvorba balíčků (1/2) – Soudržnost 14.11.2012
  12. Návrhové principy: Tvorba balíčků (2/2) – Závislosti a provázanost 14.1.2013

V tomto díle stručně projdeme tři principy, které poskytují vodítka k samotné struktuře kódu. Jde o několik jednoduchých zásad umožňujících nám lépe uvažovat o rozdílech mezi doménovým modelem a jeho reálnou implementací.

Pozn. V tomto díle jsem původně plánoval projít principy Information Expert a Creator, ale nakonec jsem se rozhodl z důvodu lepší návaznosti pořadí změnit.

Polymorphism

Polymorfismus je jednou ze základních vlastností objektového programování. Jde o velmi účinný nástroj pro zjednodušení kódu, který bychom měli umět správně využívat a nahradit jím méně vhodné konstrukce. GRASP formalizuje tuto zásadu jako:

Pokud chování závisí na typu objektu (třídě), přiřaďte zodpovědnost za toto chování pomocí polymorfických metod třídě, na které toto chování závisí.

Jinými slovy nikdy neřiďte chování pomocí podmínek testujících typ objektu. Místo toho zavolejte metodu objektu, která zajistí požadované chování sama. Jednotlivé podtřídy pak mohou samy ovlivnit požadované chování.

Pokud tento princip není dodržen, tak přidání každé další podtřídy vyžaduje úpravu na všech místech, kde se dříve testoval typ objektu. Na všech těchto místech by bylo nutné určit, jak se zachovat v případě, že bude zpracováván objekt nové podtřídy. Informace o chování jsou tedy roztříštěné na mnoho míst kódu (což mimo jiné porušuje princip Don’t repeat yourself – DRY).

Pokud návrh dodržuje tento princip, je rozšíření o nové podtřídy v zásadě jednoduché. Stačí vytvořit novou podtřídu, která si sama překrytím polymorfní metody určí, jaké bude chování při práci s ní. Díky tomu je možné snadno měnit chování systému vytvářením a používáním nových podtříd.

Polymorfismus se ale nemusí vztahovat čistě na vytváření podtříd. Tato zásada se vztahuje na jakoukoliv třídu, která implementuje stejné rozhraní. Návrhový vzor Proxy ukazuje, jak lze snadno při použití polymorfismu vytvořit proxy objekt, který je pak možné použít kdekoliv, kde by byl použit původní objekt, bez nutnosti jakéhokoliv zásahu. Tento proxy objekt pak může změnit chování původního objektu právě s využitím polymorfismu. Potřebná změna chování je ale opět zapouzdřena v proxy a není nutné v jiných částech kódu ošetřovat, zda pracujeme s původním objektem nebo jeho proxy.

Pokud používáme polymorfismus je nutné dodržovat Liskovové substituční princip popsaný v díle o SOLID principech. Tento princip říká, že „podtřídy by měly být zaměnitelné s jejich bázovými třídami“. Při nedodržení této zásady mi mohl původní kód přestat fungovat v případě, že by mu byla předána podtřída s nekompatibilním chováním.

Polymorfismus a abstrakce jsou také základním prostředkem pro splnění Open-closed principle popsaného ve stejném díle. Díky vytváření nových podtříd, které překrývají a mění chování abstraktních předků, je možné rozšiřovat kód o nové funkce, aniž by bylo nutné zasahovat do kódu dříve vytvořených podtříd.

S tímto principem souvisí také princip Protected variations popsaný v prvním díle o GRASP. Použití polymorfismu izoluje změny potřebné při vytvoření nové podtřídy do této podtřídy a chrání tak ostatní části systému před nežádoucími zásahy.

Z hlediska návrhu může být výhodné použít polymorfismus i v případech, kdy v aktuálním systému neexistuje potřeba měnit chování na základě typu objektu, ale je pravděpodobné, že se tato potřeba objeví v budoucnosti. Vždy bychom ale měli být realističtí ohledně pravděpodobnosti těchto změn. Pokud by ke změně nedošlo, mohlo by jít o zbytečně investované úsilí.

Tento princip je použit například v návrhových vzorech State, Strategy, Adapter, Command, Proxy a dalších.

Pure fabrication

V některých případech by přiřazení odpovědnosti některé třídě představující objekt z problémové domény narušilo soudržnost (cohesion) této třídy, zvýšilo její provázání (coupling) nebo porušilo jiné principy. V takovém případě je vhodné vytvořit novou třídu, která nepředstavuje nic z oblasti domény – třídu vytvořenou pouze pro zlepšení kvality návrhu.

Takovéto třídy nazýváme pure fabrication (neexistuje žádný vhodný český překlad, významově by asi bylo nejbližší něco jako „pouhé konstrukční prvky“).

Třídy představující pure fabrication nereprezentují nic, co by existovalo v rámci problémové domény. Tyto třídy tedy nenajdeme v doménovém modelu vzniklém při analýze požadavků. Jde o třídy vytvořené čistě pro účely architektury software, které jsou identifikovány až při zpracování návrhu.

Typickým příkladem takovýchto tříd jsou třídy pro práci s databází. V problémové doméně nic jako databáze neexistuje, ale přiřazení odpovědnosti za perzistentní uložení každé třídě domény zvlášť by vedlo k nekvalitnímu návrhu. Jsou proto vytvořeny třídy pure fabrication, které tyto odpovědnosti převezmou.

Může jít také o třídy seskupující související chování, které sice je v doméně nějakým způsobem reprezentováno, ale jsou důvody, proč jej extrahovat do oddělené třídy. Může jít například o různé pomocné třídy nebo algoritmy.

Pure fabrication by ale mělo být používáno, pouze pokud ostatní řešení, která nevyžadují pure fabrication, mají jasné nevýhody. Vytváření pure fabrication je totiž obvykle v rozporu s principem Information expert (viz příští díl). Odděluje totiž zpracování informací od objektů, které tyto informace ukládají. Pokud by bylo použito do extrému, vedlo by k návrhu, který by v podstatě představoval procedurální programování, kde by funkce byly pouze seskupeny do objektů.

Většina návrhových vzorů představuje pure fabrication.

Indirection

Jak přiřadit zodpovědnosti, pokud se potřebujeme vyhnout přímé vazbě? Přiřaďte zodpovědnost prostředníkovi, který zprostředkuje propojení mezi prvky, takže nebudou muset být propojeny přímo.

Hlavní motivace pro nepřímá propojení je snižování provázanosti (coupling). Třídy používané jako prostředníci představují pure fabrication.

Larman uvádí staré pořekadlo OO návrhu: „Většina problémů může být vyřešena přidáním další úrovně nepřímosti.“ Zde je ovšem nutné také uvést komplementární poučku: „Většina problémů s výkonem může být vyřešena ubráním nějaké úrovně nepřímosti.“

Použití nepřímých vazeb snižuje provázání kódu. Třídy zachycující chování systému spolu nemusejí být vůbec provázány. Tyto nezbytné vazby jsou zachyceny v prostřednících. Při změně vazeb pak obvykle stačí upravit prostředníka a není nutné upravovat všechny třídy, které by závisely přímo. Díky tomu je snížen dopad změn a dodržen princip Protected variantions.

Opět stejně jako u pure fabrication platí, že většina návrhových vzorů je realizací této zásady. Mezi nejtypičtější příklady patří vzory Adapter, Bridge a Facade. Ale i další návrhové vzory tento princip využívají – například Abstract Factory představuje prostředníka mezi uživatelem a konstruktorem.

Pokračování příště

V dalším díle se podíváme na principy Information Expert – Informační expert a Creator – Tvůrce, které představují základní principy pomáhající při výběru objektů pro přidělení zodpovědnosti podle GRASP.

Zdroje a další informace

  • Craig Larman: Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and the Unified Process (2nd Edition), Prentice Hall PTR, 2001, ISBN 978–0130925695
  • http://en.wikipedia.org/wi­ki/GRASP_(object-oriented_design)
  • Robert C. Martin: Čistý kód, Computer Press a.s., 2009, ISBN-978–80–251–2285–3
  • http://voho.cz/wiki/infor­matika/oop/princip-grasp/
  • Glenford J. Meyers: Reliable software through composite design, Petrocelli/Charter, 1975, ISBN 978–0884052845
  • Rudolf Pecinovský: Návrhové vzory, Computer Press a.s., 2007, ISBN-978–80–251–1582–4
  • Kirk Pepperdine: Nevyužité příležitosti k polymorfismu, 97 klíčových znalostí programátora, Computer Press a.s., 2010, ISBN-978–80–251–3145–9 [EN verze na webu]

Martin Jonáš pracuje jako projektový manažer v GrowJOB institute. Vystudoval Informační systémy na Fakultě informačních technologií VUT.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Zdroj: https://www.zdrojak.cz/?p=3690