Wzorce projektowe (w ASP.NET i nie tylko)

64
Wzorce projektowe w ASP.NET Bartłomiej Zass Microsoft

description

Omówienie podstawowych wzorców projektowych oraz zasad architektonicznych na przykładzie aplikacji ASP.NET, ale w większości niezależnych od stosowanej technologii. Najważniejsze założenia domain-driven design, SOLID principles, itp.

Transcript of Wzorce projektowe (w ASP.NET i nie tylko)

Page 1: Wzorce projektowe (w ASP.NET i nie tylko)

Wzorce projektowe w ASP.NETBartłomiej ZassMicrosoft

Page 2: Wzorce projektowe (w ASP.NET i nie tylko)

Keep It Simple Stupid (KISS) Don’t Repeat Yourself (DRY) Tell, Don’t Ask (reguła Hollywood)

Wydajemy polecenie obiektom, zamiast pytać o ich stan i wykonywać akcję

You Ain’t Gonna Need It (YAGNI) – tylko to, co niezbędne

Separation of Concerns (SoC)

Główne zasady

Page 3: Wzorce projektowe (w ASP.NET i nie tylko)

Single Responsibility Principle (SRP) Nie monolityczna konstrukcja (scyzoryk), 1 powód do zmiany stanu

Open-Closed Principle (OCP) Klasy powinny być otwarte na rozszerzenia, ale zamknięte na zmiany

(brak problemów podczas modyfikacji klas bazowych) Liskov Substitution Principle (LSP)

Możliwość podmienienia każdej dziedziczącej klasy z klasą bazową, bez wpływu na działanie

Interface Segregation Principle (ISP) Grupowanie interfejsu na mniejsze

Dependency Inversion Principle (DIP) Zależność od abstrakcji, nie konkretnej implementacji Inversion of Control (IoC) – kontener / framework wstrzykujący konkretną implementację

(odwrócenie kontroli) Dependency Injection (DI) – wstrzykiwanie implementacji przez konstruktor, metodę lub

właściwość

Zasady SOLID

Page 4: Wzorce projektowe (w ASP.NET i nie tylko)

Test-driven Development (TDD) Zaczynamy od pisania testu nieistniejącej jeszcze

funkcjonalności Red-Green (od narzędzi)

Domain-driven Design (DDD) Wierne modelowanie logiki biznesowej w kodzie Ten sam język, używany przez biznes

Behavior-driven Design (BDD) Evolucja TDD połączona z DDD Dokumentacja, specyfikacje, testy sprawdzające zgodność

z założeniami

Inne praktyki

Page 5: Wzorce projektowe (w ASP.NET i nie tylko)

Typowa architektura aplikacji

Page 6: Wzorce projektowe (w ASP.NET i nie tylko)

Model Obiekty domenowe, logika, relacje Interfejsy potrzebne do zapisu (Repository) Brak referencji do infrastruktury pod spodem

Repository Referencja do modeli Implementacja interfejsów repozytorium z projektu modelu

Application Service Gateway do aplikacji Komunikacja z frontendem przez DTO ViewModele

Web Komunikacja wyłącznie z Application Service W odpowiedzi ViewModele

Podział na projekty

Page 7: Wzorce projektowe (w ASP.NET i nie tylko)

Organizacja warstwy logiki biznesowej

Page 8: Wzorce projektowe (w ASP.NET i nie tylko)

Proste, proceduralne podejście Np. statyczna klasa

Proste, dobre dla małych aplikacji Mniej wymagające dla programistów

Trudne w utrzymaniu, kiedy aplikacja się rozrasta

Transaction Script

Page 9: Wzorce projektowe (w ASP.NET i nie tylko)

Efektywne, kiedy struktura bazy odzwierciedla model biznesowy Np. blog

Każdy obiekt odpowiada za zapis swojego stanu Narzędzia do generacji kodu z bazy Najpopularniejsze

Ruby on Rails Castle ActiveRecord (.NET)

Problemy, kiedy model model biznesowy „rozjeżdża” się z bazą Tzw. Impedance Mismatch

Active Record

Page 10: Wzorce projektowe (w ASP.NET i nie tylko)

Castle Activerecord - przykład

            Post post = Post.Find(postId);

            Comment comment = new Comment();            comment.Post = post;            comment.Author = Request.Form["Author"];            comment.DateAdded = DateTime.Now;            comment.Text = Request.Form["Comment"];

            comment.Save();

    [ActiveRecord("Comments")]    public class Comment : ActiveRecordBase<Comment>     {               [PrimaryKey]        public int Id { get; set; }

        [BelongsTo("PostID")]        public Post Post { get; set; }

        [Property]        public string Text { get; set; }

        [Property]        public string Author { get; set; }

        [Property]        public DateTime DateAdded { get; set; }    }

Page 11: Wzorce projektowe (w ASP.NET i nie tylko)

Całkowite odzwierciedlenie modelu biznesowego w obiektach Nie koniecznie 1:1 z bazą Nie tylko pojemniki na dane Także logika – np. walidacja, relacje między obiektami

Obiekty nie wiedzą jak się zapisać POCO (Plan Old CLR Object) i PI (Persistence Ignorance)

Domain Service Kiedy akcja nie może być wewnątrz samego obiektu Np. akcje transferu między dwoma kontami (korzysta z IRepository –

same encje nie powinny korzystać bezpośrednio z IRepository) Proste do unit testów!

Domain Model

Page 12: Wzorce projektowe (w ASP.NET i nie tylko)

ViewMapper – generuje ViewModele na podstawie modelu

Messaging Klasa bazowa + odpowiednie Request i Response

Application Service (frontend) Koordynuje wszystkie aktywności aplikacji Deleguje zadania do modelu domenowego Może korzystać z repozytorium, kiedy trzeba (np. nowe

konto) Odbiera wiadomości – wykonuje akcje – odpowiada

wiadomością Transformuje encje modelu na DTO dla warstwy

prezentacji

Domain Model – c.d.

Page 13: Wzorce projektowe (w ASP.NET i nie tylko)

Antywzorzec Podobne do Domain Model Wszelkie akcje nie wewnątrz obiektów, ale poza

modelem Tak naprawdę DTO

Domain Services w stylu Transaction Script Naruszenie zasady „Tell, don’t ask”

Anemic Domain Model

Page 14: Wzorce projektowe (w ASP.NET i nie tylko)

Metodyka bazująca na wzorcu Domain Model Wspólny język deweloperów, ekspertów dziedzinowych

Usprawnia komunikację między wykonawcami i biznesem Ułatwia deweloperom zrozumienie reguł biznesowych

Encje Unikalne, mają identyfikator (np. pesel lub inkrementowany int)

Value Objects Nie mają ID Nie żyją same z siebie (np. Transaction – żyje tylko w powiązaniu z Bank Account)

Aggregate Logicznie pogrupowane obiekty pod względem celu modyfikacji danych

Agreggate Root Jedyne encje, do których jest dostęp z zewnątrz agregatu Np. dla ecommerce – Order (bo OrderLine czy aplikacja Voucheru zawsze przez Order –

walidacja, itp..)

Domain Driven Design

Page 15: Wzorce projektowe (w ASP.NET i nie tylko)

Domain Services Metody nie pasujące do encji lub wymagające dostępu do repozytorium Mogą także zawierać logikę biznesową – jest to część modelu domenowego

Application Services Cienka warstwa pomiędzy modelem i aplikacją Brak logiki biznesowej Nie przechowuje stanu encji Może przechowywać stan workflowu

Repository Odpowiada za zapis danych

Podział na warstwy

DDD – c.d.

Page 16: Wzorce projektowe (w ASP.NET i nie tylko)

Wzorce warstwy logiki biznesowej

Page 17: Wzorce projektowe (w ASP.NET i nie tylko)

Creational pattern (GoF) Ukrywanie skomplikowanego tworzenia obiektów Z reguły klient nie prosi o konkretną klasę

Oczekujemy klasy abstrakcyjnej lub interfejsu Factory decyduje jaka konkretna implementacja ma być

zwrócona

Factory

Page 18: Wzorce projektowe (w ASP.NET i nie tylko)

Factory – c.d. np. Factory zwracające obiekt generujący etykiety

adresowe

Page 19: Wzorce projektowe (w ASP.NET i nie tylko)

Nowe cechy dodawane przez kompozycję Unikamy tworzenia ogromnej liczby dziedziczących klas Np. dodanie zniżki lub przelicznika waluty, logowanie,

strumienie

Decorator

Page 20: Wzorce projektowe (w ASP.NET i nie tylko)

Struktura metody zdefiniowana Cześć metod do zdefiniowania przez dziedziczące

klasy

Template method

Page 21: Wzorce projektowe (w ASP.NET i nie tylko)

Zmiana zachowania przy zmianie stanu wewnętrznego Podmiana wewnętrznych obiektów odpowiadających za

zachowania

State

Page 22: Wzorce projektowe (w ASP.NET i nie tylko)

Pozwala wybierać algorytm w czasie wykonywania

Strategy

Page 23: Wzorce projektowe (w ASP.NET i nie tylko)

Nic nie robi Nie chcemy nie wyrzucać wyjątku, ale zgodne z

interfejsem Np. brak strategii

Null Object

    public class NoBasketDiscount : IBasketDiscountStrategy     {        public decimal GetTotalCostAfterApplyingDiscountTo(Basket basket)        {            return basket.TotalCost;         }         }

Page 24: Wzorce projektowe (w ASP.NET i nie tylko)

Pozwala kolekcje traktować tak jak pojedynczą instancję

Kompozyt

Page 25: Wzorce projektowe (w ASP.NET i nie tylko)

Kompozyt - przykład

        //Component        public interface IGraphic        {            void Print();        }        //Leaf        public class Ellipse : IGraphic        {            //Prints the graphic            public void Print()            {                Console.WriteLine("Ellipse");            }        }

       public class CompositeGraphic : IGraphic        {            //Collection of Graphics.            private readonly List<IGraphic> graphics;

            //Constructor             public CompositeGraphic()            {                //initialize generic Colleciton(Composition)                graphics = new List<IGraphic>();            }            //Adds the graphic to the composition            public void Add(IGraphic graphic)            {                graphics.Add(graphic);            }            //Adds multiple graphics to the composition            public void AddRange(params IGraphic[] graphic)            {                graphics.AddRange(graphic);            }            //Removes the graphic from the composition            public void Delete(IGraphic graphic)            {                graphics.Remove(graphic);            }            //Prints the graphic.            public void Print()            {                foreach (var childGraphic in graphics)                {                    childGraphic.Print();                }            }        }

Page 26: Wzorce projektowe (w ASP.NET i nie tylko)

Specyfikacja – zapisanie prostej reguły (IsSatisfiedBy()) + np. kompozyt – zagregowanie wielu mniejszych

specyfikacji

Kompozyt i specyfikacja

Page 27: Wzorce projektowe (w ASP.NET i nie tylko)

Iterator HasNext, GetNext

Visitor Kiedy potrzebujemy wykonać akcję na danych encjach

skomplikowanej struktury (np. agent, który chodzi po drzewie)

Visitor, Iterator

Page 28: Wzorce projektowe (w ASP.NET i nie tylko)

W C# w zasadzie gotowe – eventy, delegaty Lubi powodować wycieki pamięci

Strong reference Weak Reference

Observer

Page 29: Wzorce projektowe (w ASP.NET i nie tylko)

Lock, podwójna weryfikacja, static, IoC BeforeFieldInit – inicjalizacja bardziej lazy (na początku

metody, która może jej potrzebować) W praktyce – na poniższym przykładzie zawsze Bez BeforeFieldInit – może być zainicjalizowana przed użyciem Sposób: statyczny konstruktor

Singleton

        public static void DoSomething(bool which)        {            if (which)            {                FirstType.Foo();            }            else            {                SecondType.Bar();            }        }

Page 30: Wzorce projektowe (w ASP.NET i nie tylko)

Brak inversion of control

Page 31: Wzorce projektowe (w ASP.NET i nie tylko)

Dependency inversion

Page 32: Wzorce projektowe (w ASP.NET i nie tylko)

Interface Inversion – źle!

Page 33: Wzorce projektowe (w ASP.NET i nie tylko)

Interface Inversion - lepiej

Page 34: Wzorce projektowe (w ASP.NET i nie tylko)

Skąd przychodzą zależności?

Page 35: Wzorce projektowe (w ASP.NET i nie tylko)

Konstruktor

Skąd przychodzą zależności?

Page 36: Wzorce projektowe (w ASP.NET i nie tylko)

Wstrzykiwanie zależności przez kontener IoC StructureMap, Castle Windsor, Spring.NET, Ninject,

PicoContainer.NET, Unity, MEF, … Właściwość, konstruktor

Service Locator Bardziej luźno powiązane Factory*

Dependency Injection

OrderService orderService = serviceLocator.Locate<OrderService>(“OrderServiceWithFedExCourier”);

Page 37: Wzorce projektowe (w ASP.NET i nie tylko)

Kluczowe funkcjonalności te same Różne platformy wspierane Różnice przy bardziej zaawansowanych scenariuszach

Przykład - rozszerzenia – np. nasz kod w trakcie wstrzykiwania, itp. Porównanie wydajności

Najszybszy – Simple Injector

DI – który wybrać?

Page 38: Wzorce projektowe (w ASP.NET i nie tylko)

Layer Super Type Unikanie duplikacji Np. EntityBase<T>, walidacja

Interface Segregation Dzielimy duży interfejs na kilka mniejszych,

pogrupowanych logiczniezamiast jednego dużego i NotImplementedException

Liskov Substitution Principle Działanie klasy dziedziczącej powiąż z założeniami

kontraktu klasy bazowej

Inne wzorce enterprise

Page 39: Wzorce projektowe (w ASP.NET i nie tylko)

Warstwa usług

Page 40: Wzorce projektowe (w ASP.NET i nie tylko)

Wyraźne granice Interfejs jak najbardziej czytelny jak możliwe, ujednolicone

typy komunikatów Usługi są autonomiczne

Metody bezstanowe, zmiany atomic, nie konieczna określona kolejność wywołań

Współdzielenie kontraktu i schema, nie klas Kompatybilność określają polityki (np. WS-Policy)

Najważniejsze zasady SOA

Page 41: Wzorce projektowe (w ASP.NET i nie tylko)

Fasada - uproszczenie skomplikowanego API Adapter – przystosowanie interfejsu jednej klasy do

drugiej

Fasada i adapter

Page 42: Wzorce projektowe (w ASP.NET i nie tylko)

RequestMessage, ResponseMessage, … Extension methods do konwersji modelu na

komunikat response

Document Message i Request-Response

Page 43: Wzorce projektowe (w ASP.NET i nie tylko)

Długotrwały proces, wymagający przechowywania stanu i wielu komunikatów

Unikalny identyfikator po pierwszym wywołaniu Przekazywany przy kolejnych Czas ważności

Wzorzec Reservation

Page 44: Wzorce projektowe (w ASP.NET i nie tylko)

Operacja indempotentna to taka, która może być wywołana wielokrotnie z tymi samymi parametrami wejściowymi (nie wywołując błędu)

Wszystkie żądania modyfikujące stan powinny zawierać unikalny identyfikator Identyfikator sprawdzany przed przetworzeniem komunikatu Jeśli już był przetworzony – zwracana odpowiedź z response store dla danego ID Identyfikator może być zwrócony w odpowiedzi (tzw. correlation ID)

Wzorzec Indempotent

Page 45: Wzorce projektowe (w ASP.NET i nie tylko)

Warstwa dostępu do danych

Page 46: Wzorce projektowe (w ASP.NET i nie tylko)

Reprezentuje kolekcję obiektów Mogą mieć zależności z innymi repozytoriami Całkowicie wyizolowane od modelu domenowego

Interfejs separujący od konkretnej implementacji IQueryable nie zalecane

Osobne dla każdego Aggregate Root

Repository

        public interface IRepository<T>        {            IEnumerable<T> FindAll();            IEnumerable<T> FindAll(int index, int count);            IEnumerable<T> FindBy(Query query);            IEnumerable<T> FindBy(Query query, int index, int count);            T FindBy(Guid Id);            void Add(T entity);            void Save(T entity);            void Remove(T entity);        }

Page 47: Wzorce projektowe (w ASP.NET i nie tylko)

Podobna koncepcja do Repository, ale na niższym poziomie Nie ukrywa, że reprezentuje tabelę z bazy

Z reguły jedno DAO dla jednej tabeli Wykorzystywane często przy Active Record i Transaction

Script

Data Access Objects

        public interface IProductDAO        {            Product Get(int id);            IEnumerable<Product> FindByCategory(int id);            IEnumerable<Product> FindByBrand(int id);            IEnumerable<Product> FindByTopSelling(int count);            void Add(Product product);            void Save(Product product);            void Remove(Product product);        }

Page 48: Wzorce projektowe (w ASP.NET i nie tylko)

Rejestruje zmiany w obiektach biznesowych Dodanie, usunięcie, zmiana

Koordynuje zapis zmian w bazie Transakcja, konflikty, itp.

Zapewnia integralność danych

RegisterAmended – przekazywana encjai repozytorium

Commit wywołuje odpowiednie metody(np. PersistUpdateOf(acc)) na odpowiednich repozyzoriach Opakowane w transakcję

Unit of Work

Page 49: Wzorce projektowe (w ASP.NET i nie tylko)

IAggregateRoot – pusty interfejs Wzorzec Marker Aplikowane do encji będących AggregateRoot

IUnitOfWorkRepository

IUnitOfWork Wstrzykiwane do repozytorium – wiele repozytoriów może uczestniczyć w transakcji

Główne składniki Unit Of Work

        public interface IUnitOfWorkRepository        {            void PersistCreationOf(IAggregateRoot entity);            void PersistUpdateOf(IAggregateRoot entity);            void PersistDeletionOf(IAggregateRoot entity);        }

        public interface IUnitOfWork        {            void RegisterAmended(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);            void RegisterNew(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);            void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);            void Commit();        }

Page 50: Wzorce projektowe (w ASP.NET i nie tylko)

IDbSet – implementacja Repository Mimo wszystko chcemy większej abstrakcji

DbContext – w zasadzie implementacja UoW Przydaje się do współdzielenia kontekstu między

repozytoriami

UoW i Entity Framework

Page 51: Wzorce projektowe (w ASP.NET i nie tylko)

Lazy Loading Natywnie w .NET – IQueryable

Proxy Maskowanie długotrwałego wywoływania operacji Cache, bezpieczeństwo

synchronizacja, …

Proxy

Page 52: Wzorce projektowe (w ASP.NET i nie tylko)

Upewnia się, że każdy obiekt został załadowany tylko raz Dostarcza tą samą wersję obiektów biznesowych

transakcji Przy dwukrotnym odwoływaniu się do obiektu, ta sama

instancja jest zwracana Z reguły stosowane w ramach jednej transakcji

Identity Map

Page 53: Wzorce projektowe (w ASP.NET i nie tylko)

Reprezentuje zapytanie w języku domenowym Unikamy pisania kodu dla każdego zestawu parametrów, np.:

Pozwala odseparować zapytanie od bazy danych QueryTranslator

Tłumaczy zapytanie na język bazy Analogiczne do providerów LINQ Lepiej działa z procedurami składowanymi

Query Object

        public interface ICustomerRepository        {            IEnumerable<Customer> FindAll();            IEnumerable<Customer> FindAllVIPCustomers();            IEnumerable<Customer> FindByOrder(Guid ID);            IEnumerable<Customer> FindAllCustomersThatHaveOutstandingOrders();        }

Page 54: Wzorce projektowe (w ASP.NET i nie tylko)

Warstwa prezentacji

Page 55: Wzorce projektowe (w ASP.NET i nie tylko)

Najpopularniejszy wzorzec dla Web Forms / Windows Forms Samodzielnie lub ew. frameworki (np. http://webformsmvp.com)

Model Model biznesowy, modyfikowany lub wyświetlany przez widok

View Wyświetla dane modelu pobierane przez Presenter Deleguje akcje użytkownika do Presentera Interfejs przekazywany do presentera (część private get / set)

Presenter Wywoływany przez widok, w celu reakcji na akcje użytkownika Może korzystać ze wstrzykiwanych zależności przez IoC Daje się testować, ma wyodrębniony interfejs, brak zależności z httpcontext

Model-View-Presenter (MVP)

Page 56: Wzorce projektowe (w ASP.NET i nie tylko)

MVP – najpopularniejsze odmiany

Page 57: Wzorce projektowe (w ASP.NET i nie tylko)

MVP Passive View

Page 58: Wzorce projektowe (w ASP.NET i nie tylko)

MVP – diagram sekwencji

Page 59: Wzorce projektowe (w ASP.NET i nie tylko)

Hermetyzacja wykonania akcji Execute, CanExecute

Np. cofnij/ponów, makra, itp.

Command

Page 60: Wzorce projektowe (w ASP.NET i nie tylko)

Kontroler pierwszy ma kontrolę, wykrywa który widok wyświetlić Front Controller Pasywny model, aktywny model Page Controller – każda strona ma swój kontroler (code behind w ASP.NET)

Generalnie najlepiej ASP.NET MVC, ale da się samemu (HttpHandlery) Łatwiejszy w utrzymaniu, ale więcej pracy

Model-View-Controller (MVC) i Front Controller

Page 61: Wzorce projektowe (w ASP.NET i nie tylko)

Command i Front Controller

Page 62: Wzorce projektowe (w ASP.NET i nie tylko)

Chain of Responsibility Łańcuch obiektów typu opakowujących akcję Po kolei – wykonanie akcji lub przekazanie dalej

np. filtry poczty, routing

Page 63: Wzorce projektowe (w ASP.NET i nie tylko)

Specjalna klasa przesyłana przez AppService do widoku (DTO)

Agregacja lub podzbiór danych modelu, potrzebne do wyświetlenia widoku

Mapowanie ręczne lub frameworki AutoMapper (http://automapper.codeplex.com)

ViewModel

Mapper.CreateMap<Order, OrderDto>();OrderDto dto = Mapper.Map<Order, OrderDto>(order);

Page 64: Wzorce projektowe (w ASP.NET i nie tylko)

© 2012 Microsoft Corporation. Wszelkie prawa zastrzeżone. Microsoft, Windows oraz inne nazwy produktów są lub mogą być znakami towarowymi lub zastrzeżonymi znakami towarowymi firmy Microsoft w Stanach Zjednoczonych i innych krajach. Zamieszczone informacje mają charakter wyłącznie informacyjny. FIRMA MICROSOFT NIE UDZIELA ŻADNYCH GWARANCJI (WYRAŻONYCH WPROST LUB DOMYŚLNIE), W TYM TAKŻE USTAWOWEJ RĘKOJMI ZA WADY FIZYCZNE I PRAWNE, CO DO INFORMACJI ZAWARTYCH W TEJ PREZENTACJI.