Programování

Úvod do návrhových vzorů, Část 1: Historie a klasifikace návrhových vzorů

Byla vyvinuta řada strategií pro zjednodušení a snížení nákladů na návrh softwaru, zejména v oblasti údržby. Naučit se, jak identifikovat a pracovat s opakovaně použitelnými softwarovými komponentami (příležitostně označovanými jako softwarové integrované obvody) je jedna strategie. Použití návrhových vzorů je další.

Tento článek uvádí třídílnou sérii návrhových vzorů. V této části představím koncepční rámec návrhových vzorů a projdu ukázkou vyhodnocení návrhového vzoru pro konkrétní případ použití. Budu také diskutovat o historii designových vzorů a anti-vzorů. Nakonec klasifikuji a shrnu nejpoužívanější vzory návrhu softwaru, které byly objeveny a zdokumentovány během posledních několika desetiletí.

Co je návrhový vzor?

Navrhování opakovaně použitelného objektově orientovaného softwaru, který modeluje stávající systém, je skutečně náročné. Softwarový vývojář musí rozdělit entity systému do tříd, jejichž veřejná rozhraní nejsou příliš složitá, navázat vztahy mezi třídami, vystavit hierarchie dědičnosti a další. Protože většina softwaru zůstává v provozu dlouho poté, co byla napsána, musí vývojáři softwaru také řešit aktuální požadavky aplikací a současně udržovat svůj kód a infrastrukturu dostatečně flexibilní, aby vyhovovaly budoucím potřebám.

Zkušení objektově orientovaní vývojáři zjistili, že vzory návrhu softwaru usnadňují kódování stabilních a robustních softwarových systémů. Efektivní opětovné použití těchto návrhových vzorů místo neustálého vývoje nových řešení od začátku je efektivní a snižuje část rizika chyb. Každý návrhový vzor identifikuje opakující se problém s návrhem v konkrétním kontextu aplikace, poté nabízí zobecněné, opakovaně použitelné řešení, které je použitelné pro různé scénáře aplikace.

"A návrhový vzor popisuje třídy a interagující objekty používané k řešení obecného konstrukčního problému v konkrétním kontextu. “

Někteří vývojáři definují a návrhový vzor jako entita kódovaná třídou (například propojený seznam nebo bitový vektor), zatímco jiní říkají, že návrhový vzor je v celé aplikaci nebo subsystému. Můj názor je, že a návrhový vzor popisuje třídy a interagující objekty používané k řešení obecného konstrukčního problému v konkrétním kontextu. Formálněji je návrhový vzor určen jako popis, který se skládá ze čtyř základních prvků:

  1. A název který popisuje návrhový vzor a dává nám slovní zásobu k jeho projednání
  2. A problém který identifikuje konstrukční problém, který je třeba vyřešit, spolu s kontextem, ve kterém se problém vyskytuje
  3. A řešení k problému, který (v kontextu vzorů softwarového designu) by měl identifikovat třídy a objekty, které přispívají k návrhu spolu s jejich vztahy a dalšími faktory
  4. Vysvětlení důsledky použití návrhového vzoru

Abyste mohli určit vhodný vzor návrhu, který chcete použít, musíte nejprve jasně identifikovat problém, který se snažíte vyřešit; to je místo, kde problém je užitečný prvek popisu návrhového vzoru. Volba jednoho návrhového vzoru před jiným také obvykle zahrnuje kompromisy, které mohou ovlivnit flexibilitu aplikace nebo systému a budoucí údržbu. Proto je důležité porozumět důsledky použití daného návrhového vzoru, než jej začnete implementovat.

Hodnocení návrhového vzoru

Zvažte úkol návrhu komplexního uživatelského rozhraní pomocí tlačítek, textových polí a dalších nekontejnerových komponent. Kompozitní návrhový vzor považuje kontejnery za komponenty, což nám umožňuje vnořit kontejnery a jejich komponenty (kontejnery a nekontejnery) do jiných kontejnerů, a to rekurzivně. Pokud bychom se rozhodli nepoužívat kompozitní vzor, ​​museli bychom vytvořit mnoho specializovaných nekontejnerových komponent (například jednu komponentu kombinující například textové pole hesla a přihlašovací tlačítko), což je těžší dosáhnout.

Když jsme si to promysleli, chápeme problém, který se snažíme vyřešit, a řešení nabízené složeným vzorem. Jaké jsou však důsledky použití tohoto vzorce?

Použití Composite znamená, že vaše hierarchie tříd budou kombinovat kontejnerové a nekontejnerové komponenty. Jednodušší klienti budou s komponentami kontejneru i bez kontejneru zacházet jednotně. A bude snazší zavést do uživatelského rozhraní nové druhy komponent. Kompozitní může také vést k příliš zobecněný vzory, což ztěžuje omezení druhů komponent, které lze přidat do kontejneru. Vzhledem k tomu, že se nebudete moci spolehnout na to, že kompilátor vynutí omezení typu, budete muset použít kontroly typu za běhu.

Co je špatného na kontrolách typu runtime?

Kontroly typu runtime zahrnují -li prohlášení a instanceof operátor, což vede k křehkému kódu. Pokud zapomenete aktualizovat kontrolu typu běhového modulu, jak se vyvíjejí požadavky vaší aplikace, můžete následně zavést chyby.

Je také možné zvolit vhodný návrhový vzor a použít jej nesprávně. The Dvojitě zkontrolované zamykání vzor je klasický příklad. Dvojitě zkontrolované zamykání snižuje režii získávání zámku tím, že nejprve otestuje kritérium zamykání, aniž by skutečně získalo zámek, a poté získá zámek pouze v případě, že kontrola naznačuje, že je nutné zamykání. I když to na papíře vypadalo dobře, dvojitá kontrola zamykání v JDK 1.4 měla nějaké skryté složitosti. Když JDK 5 rozšířil sémantiku nestálý klíčové slovo, vývojáři konečně mohli těžit z výhod dvojitě kontrolovaného uzamykacího vzoru.

Více o dvojitě zkontrolovaném zamykání

Viz „Dvojitě zkontrolované zamykání: Chytré, ale poškozené“ a „Lze dvojitě zkontrolované zamykání opravit?“ (Brian Goetz, JavaWorld), kde se dozvíte více o tom, proč tento vzor nefungoval v JDK 1.4 a starších. Další informace o specifikaci DCL v JDK 5 a novějších naleznete v prohlášení „Deklarace„ Double-Checked Locking is Broken ““ (University of Maryland Department of Computer Science, David Bacon a kol.).

Anti-vzory

Pokud se návrhový vzor běžně používá, ale je neúčinný a / nebo kontraproduktivní, je návrhový vzor znám jako anti-vzor. Někdo by mohl namítnout, že dvojitě kontrolované zamykání, jak se používá v JDK 1.4 a dřívějších verzích, bylo anti-vzor. Řekl bych, že to byl v této souvislosti pouze špatný nápad. Aby se špatný nápad vyvinul do anti-vzoru, musí být splněny následující podmínky (viz Zdroje).

  • Opakovaný vzorec akce, procesu nebo struktury, který se zpočátku zdá být prospěšný, ale nakonec přináší více špatných důsledků než prospěšných výsledků.
  • Existuje alternativní řešení, které je jasně zdokumentováno, prokázáno v praxi a opakovatelné.

Zatímco dvojitě kontrolované zamykání v JDK 1.4 splňovalo první požadavek anti-vzoru, nesplňovalo druhý: ačkoli jste mohli použít synchronizované Chcete-li vyřešit problém líné inicializace v prostředí s více podprocesy, bylo by to na prvním místě překonáno důvodem použití dvojitého zamykání.

Zablokování anti-vzory

Rozpoznání anti-vzorů je nezbytnou podmínkou, jak se jim vyhnout. Přečtěte si třídílnou sérii Obi Ezechukwu pro úvod ke třem anti-vzorům, které jsou známé tím, že způsobily zablokování:

  • Žádné rozhodčí řízení
  • Agregace pracovníků
  • Inkrementální zamykání

Historie návrhových vzorů

Designové vzory se datují koncem sedmdesátých let vydáním Jazyk vzoru: města, budovy, stavba architekt Christopher Alexander a několik dalších. Tato kniha představila návrhové vzory v architektonickém kontextu a představila 253 vzorů, které společně tvořily to, co autoři nazvali a vzorový jazyk.

Ironie designových vzorů

Ačkoli návrhové vzory používané pro návrh softwaru vysledují jejich počátek Vzorový jazyk, toto architektonické dílo bylo ovlivněno tehdy vznikajícím jazykem popisujícím počítačové programování a design.

Koncept vzorového jazyka se následně objevil u Donalda Normana a Stephena Drapera Návrh systému zaměřeného na uživatele, která byla vydána v roce 1986. Tato kniha navrhla použití vzorových jazyků na návrh interakce, což je praxe navrhování interaktivních digitálních produktů, prostředí, systémů a služeb pro lidské použití.

Kent Beck a Ward Cunningham mezitím začali studovat vzory a jejich použitelnost v softwarovém designu. V roce 1987 použili řadu návrhových vzorů, aby pomohli skupině Tektronix Semiconductor Test Systems Group, která měla potíže s dokončením designového projektu. Beck a Cunningham následovali Alexandrovu radu ohledně designu zaměřeného na uživatele (umožnili zástupcům uživatelů projektu určit výsledek návrhu) a zároveň jim poskytli některé návrhové vzory pro usnadnění práce.

Erich Gamma si při práci na své disertační práci také uvědomil důležitost opakujících se návrhových vzorů. Věřil, že návrhové vzory by mohly usnadnit úkol psaní opakovaně použitelného objektově orientovaného softwaru, a přemýšlel, jak je efektivně dokumentovat a komunikovat. Před evropskou konferencí o objektově orientovaném programování v roce 1991 začali Gamma a Richard Helm katalogizovat vzory.

Na workshopu OOPSLA, který se konal v roce 1991, se ke Gama a Helmovi připojili Ralph Johnson a John Vlissides. Tento Gang čtyř (GoF), jak byli následně známí, pokračoval v psaní populárního Návrhové vzory: Prvky opakovaně použitelného objektově orientovaného softwaru, který dokumentuje 23 návrhových vzorů ve třech kategoriích.

Moderní vývoj designových vzorů

Návrhové vzory se od původní knihy GoF nadále vyvíjely, zejména proto, že vývojáři softwaru čelili novým výzvám souvisejícím se změnami požadavků na hardware a aplikace.

V roce 1994 byla slavnostně otevřena americká nezisková organizace známá jako Hillside Group Vzorové jazyky programů, skupina výročních konferencí, jejichž cílem je rozvíjet a zdokonalovat umění vzorů softwarového designu. Tyto probíhající konference přinesly mnoho příkladů návrhových vzorů specifických pro doménu. Například návrhové vzory v kontextu souběžnosti.

Christopher Alexander ve společnosti OOPSLA

Hlavní projev OOPSLA 96 přednesl architekt Christopher Alexander. Alexander se zamyslel nad jeho prací a nad tím, jak objektově orientovaná programovací komunita zasáhla a minula cíl při přijímání a přizpůsobování svých představ o vzorových jazycích softwaru. Můžete si přečíst Alexandrovu adresu: „Počátky teorie vzorů: budoucnost teorie a generace živého světa.“

V roce 1998 Mark Grand propuštěn Vzory v Javě. Tato kniha obsahovala návrhové vzory, které nebyly v knize GoF nalezeny, včetně vzorů souběžnosti. Grand také použil Unified Modeling Language (UML) k popisu návrhových vzorů a jejich řešení. Příklady knihy byly vyjádřeny a popsány v jazyce Java.

Softwarové návrhové vzory podle klasifikace

Moderní vzory návrhu softwaru jsou široce rozděleny do čtyř kategorií na základě jejich použití: kreační, strukturální, behaviorální a souběžnost. Budu diskutovat o každé kategorii a poté uvedu a popíšu některé prominentní vzory pro každou z nich.

Jiné typy návrhových vzorů

Pokud si myslíte, že existuje více typů vzorů, máte pravdu. Pozdější článek v této sérii pojednává o dalších typech návrhových vzorů: interakční, architektonické, organizační a komunikační / prezentační vzory.

Tvůrčí vzory

A kreační vzor abstrahuje proces vytváření instancí a odděluje, jak jsou objekty vytvářeny, skládány a reprezentovány z kódu, který se na ně spoléhá. Třída kreační vzory použít dědičnost ke změně tříd, které jsou instancovány, a objektové vzory delegovat instanci na jiné objekty.

  • Abstraktní továrna: Tento vzor poskytuje rozhraní k zapouzdření skupiny jednotlivých továren, které mají společné téma, aniž by zadali své konkrétní třídy.
  • Stavitel: Odděluje konstrukci složitého objektu od jeho reprezentace a umožňuje stejnému konstrukčnímu procesu vytvářet různé reprezentace. Abstrahování kroků konstrukce objektu umožňuje různým implementacím kroků konstrukci různých reprezentací objektů.
  • Tovární metoda: Definuje rozhraní pro vytvoření objektu, ale umožňuje podtřídám rozhodnout, kterou třídu vytvořit instanci. Tento vzor umožňuje třídě odložit instanci na podtřídy. Závislost injekce je související vzor. (Viz Zdroje.)
  • Líná inicializace: Tento vzor nám dává způsob, jak odložit vytvoření objektu, vyhledání databáze nebo jiný drahý proces, dokud nebude poprvé potřeba výsledek.
  • Multiton: Rozšiřuje koncept singletonu o správu mapy pojmenovaných instancí tříd jako páry klíč – hodnota a poskytuje k nim globální přístupový bod.
  • Fond objektů: Udržujte sadu inicializovaných objektů připravenou k použití, místo aby byla přidělena a zničena na vyžádání. Záměrem je vyhnout se nákladnému získávání a rekultivaci zdrojů recyklací předmětů, které se již nepoužívají.
  • Prototyp: Určuje druhy objektů, které mají být vytvořeny pomocí prototypové instance, a poté vytvořením nových objektů zkopírováním tohoto prototypu. Prototypová instance je klonována za účelem generování nových objektů.
  • Získávání zdrojů je inicializace: Tento vzor zajišťuje, že zdroje jsou automaticky a správně inicializovány a znovu získány jejich vázáním na životnost vhodných objektů. Prostředky jsou získávány během inicializace objektu, když není pravděpodobné, že by byly použity dříve, než budou k dispozici, a uvolní se zničením stejných objektů, což je zaručeno i v případě chyb.
  • jedináček: Zajišťuje, že třída má pouze jednu instanci a poskytuje globální přístupový bod k této instanci.
$config[zx-auto] not found$config[zx-overlay] not found