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 MVC MVVM ...
UI
UI fasády Business Layer Repository
Query
Entity Framework
Data Access Layer
Data Access Layer • Entity Framework • EDMX model • Datové entity • Rozhraní IEntity
• 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