Design Patterns Tomáš Herceg Microsoft MVP (ASP.NET) www.dotnetcollege.cz
Základní návrhové vzory Kategorie Creational Patterns starají se o vytváření instancí Structural Patterns struktura komponent v systému, rozčlenění Behavioral Patterns samotné chování systému komunikace a interakce mezi objekty
Creational Patterns Factory Abstract Factory Prototype Singleton
Factory Metoda, která na základě nějakých pravidel vrací instance třídy T nebo jejích potomků konkrétní typ není "natvrdo" v kódu např. třída DataAccessFactory metoda Create podle konfigurace vrátí buď instanci třídy PlainTextFileDataAccess SqlDataAccess všechny dědí ze třídy DataAccess
Abstract Factory Chceme vytvářet rodiny "podobných" objektů opět nemáme konkrétní typy přímo v kódu
Prototype Prototyp předpřipravený inicializovaný objekt metoda Clone() vytvoří kopii objektu podle daného prototypu V.NETu rozhraní ICloneable
Singleton "anti-pattern" zaručuje, že v aplikaci bude nejvýše 1 instance dané třídy statická metoda GetInstance vytvoří instanci nebo vrátí již vytvořenou problémy obtížná testovatelnost nelze rozumně mockovat
Singleton "anti-pattern" zaručuje, že v aplikaci bude nejvýše 1 instance dané třídy statická metoda GetInstance vytvoří instanci nebo vrátí již vytvořenou problémy obtížná testovatelnost nelze rozumně mockovat
Structural Patterns Adapter Bridge Composite Decorator Facade Proxy
Adapter někdy též Wrapper převedení jednoho rozhraní na jiné znovupoužitelnost jedna třída "obsluhuje "několik rozhraním kdykoliv je možné doplnit další bez zásahu do samotné třídy zpětná kompatibilita
Decorator dynamické přidávání dodatečné funkcionality konkrétním objektům na místech, kde podědění třídy a přidání funkce není praktické nemáme vícenásobnou dědičnost
Decorator
Composite hierarchie, každý uzel má stejné rozhraní např. strom komponent ve formuláři např. reprezentace aritmetických výrazů
Façade "Vytažení" některých funkcí ze složitější struktury objektů do nového rozhraní
Flyweight Obrovské množství objektů Několika málo typů Na identitě objektu nesejde, důležitý je typ Stav objektů je definován mimo ně Dají se znovupoužívat Flyweight mechanismus pro sdílení instancí
Flyweight
Proxy Abstrakce nad vzdálenými objekty Odložení dlouhotrvajících operací až na chvíli, kdy jsou potřeba Kontrola přístupu k objektu Varianty remote proxy: například Web Services virtual proxy: odložení dlouhotrvajících operací protection proxy: řízení přístupu k objektu
Proxy
Behavioral Patterns Chain of Responsibility Command Iterator Observer Strategy Visitor
Chain of Responsibility Řetěz objektů se stejným rozhraním Pokud první objekt nedokáže obsloužit požadavek, předá jej druhému atd.
Command Volání metod nebo provádění operací se zabalí do objektů usnadňuje asynchronní zpracování implementace undo řazení požadavků do fronty atd.
Command
Iterator Mechanismus pro procházení kolekcí, polí, sekvencí atd. Kolekce nemusí být celá uložená v paměti, ale může se generovat "on demand" V.NETu IEnumerable trochu jiné rozhraní, ale funkce podobná
Iterator
Observer Události Notifikace o změnách objektu
Strategy výběr implementace v závislosti na kontextu
Visitor rozšíření možností hierarchie zvenčí typicky u stromové struktury
Enterprise vzory
Domain Model Business data a business operace reprezentována pomocí objektů a jejich metod Nemusí být 1:1 se schématem databáze Ani by neměl být Návrh aplikace by měl začít právě návrhem domain modelu Praxe je často jiná Alternativy Data v SQL databázi, práce s nimi např. přes stored procedury, v aplikaci není nutná třída pro reprezentaci záznamu z databáze, používá se např. DataSet, DataTable Dnes již překonané
Data Mapper Mapování dat ze SQL databáze (případně jiné) na objekty doménového modelu Typicky řeší i vazby mezi tabulkami Lazy loading, eager loading Dědičnost Table per class Table per type Table per hierarchy ORM je implementací Data Mapperu a dalších vzorů
Identity Map Řeší konkurenční přístup k datům v rámci jedné transakce Např. načteme řádek z tabulky Order s Id=1 Upravíme na něm nějakou vlastnost Řádek načteme znovu (třeba jako součást jiného dotazu) Která verze platí? Identity Map v rámci každé transakce eviduje všechny entity (podle primárního klíče) Pokud již entita existuje, není materializována znovu, ale použije se existující instance
Unit of Work Ohraničuje business transakci Typicky propojená s Identity Map Eviduje změněné objekty a umožňuje promítnout jejich změny do datového úložiště Řeší i pořadí updatů Často používá IDisposable a vzor Registry Vytvoření instance zaregistruje Unit of Work do aktuálního vlákna Podpora vnořování UOW použijeme Stack Dispose Unit of Work odregistruje
Repository Umožňuje CRUD operace nad kolekcí objektů Např. databázovou tabulkou Add, Update, Delete, FindById Někdo umožňuje i vracení IQueryable V praxi není úplně vhodné Svádí to k psaní složitých dotazů přímo přes repozitář Jednoduché dotazy se v aplikaci často opakují Lepší je použít Query objekt
Query Object Dotaz nad daty reprezentován pomocí třídy Metoda Execute Další možnosti Parametrizovatelnost dotazů Obecná podpora stránkování, řazení, filtrování Možnost přidat např. metodu GetTotalCount Post-processing výsledků
Příklad architektury UI MVC MVVM... UI fasády Business Layer Repository Query Entity Framework Data Access Layer
Data Access Layer Entity Framework EDMX model Datové entity Rozhraní IEntity<TKey> Povinná vlastnost Id
Business Layer Repozitáře GetById Insert Update Delete Žádné složité dotazy Query objekty Stránkování Řazení Filtrování Jediná možnost, jak se dotazovat databáze na více hodnot Vrací Data Transfer Objekty
Business Layer Fasády Třídy s metodami připravenými pro uživatelské rozhraní Vrací DTO, přijímají DTO Vyhazují výjimky (ty ošetří UI), kontrolují oprávnění Připraveny být vystaveny jako web service Nezávislé na prezentační vrstvě Unit Of Work Ohraničuje business transakci Poskytuje abstrakci nad Entity Frameworkem Repozitáře a Queries jej používají pro komunikaci s DB
Business Layer Business objekty Pro složitější entity (např. objednávka včetně položek, dodavatelů a všech přidružených dat) Create vytvoří a zinicializuje nový Load načte objekt z databáze Save zpropaguje změny do databáze (přidání položek, vyhození položek, změna dodavatele atd.) Další metody pro příslušné procesy Identity Map Zabraňuje vzniku více instancí jednoho BO v rámci jedné Unit of Work