Metodyka projektowania obiektowego Zajęcia 4 Wzorce projektowe PW
Treść Wprowadzenie: historia, motywacja Katalog wzorców na podstawie klasycznej pozycji Design Patterns, Elements of Reusable OO Software Wzorce kreacyjne Wzorce strukturalne Wzorce behawioralne Podobieństwa wzorców Podsumowanie i wnioski Ćwiczenia 2
Motywacja Powtórne wykorzystanie sprawdzonych rozwiązań? Oczywiście! Przecież: Typowe problemy można rozwiązywać w powtarzalny sposób. Sposoby rozwiązania można przedstawić na tyle abstrakcyjnie, aby były możliwe do wykorzystania w różnych kontekstach. Znajomość katalogu typowych rozwiązań powinna przyspieszyć rozwiązanie konkretnego problemu, a wynik będzie do pewnego stopnia sprawdzony. Motto: dobre projekty mają pewne cechy wspólne. 3
Wzorce w programowaniu Wzorce w inżynierii oprogramowania: wzorce implementacyjne poziom języka programowania algorytmy sposoby rozwiązywania problemów obliczeniowych wzorce projektowe interakcja między klasami wzorce architektoniczne sposób integracji komponentów wzorce analityczne poziom opisu rzeczywistości katalog przypadków użycia poziom modelowania 4
Dawno, dawno temu... Egipcjanie, Hindusi, Tybetańczycy, Chińczycy, Grecy, Rzymianie,... 5
Historia: 1977 Wzorzec opisuje problem, który powtarza się wielokrotnie w danym środowisku, oraz podaje istotę jego rozwiązania w taki sposób, aby można było je zastosować miliony razy bez potrzeby powtarzania tej samej pracy Christopher Alexander A pattern language Wzorzec projektowy = zestaw sprawdzonych koncepcji architektonicznych służących konstruowaniu środowiska mieszkalnego i środowiska pracy zarówno dla jednostek jak i dla społeczności. 6
Historia: 1987,,Alexander zaproponował, aby domy i biura projektowali ich przyszli użytkownicy. Uważa on, ze ci ludzie najlepiej wiedzą, czego oczekują od określonej budowli. Zgadzamy się z tym i uważamy, że dotyczy to również programów komputerowych. Użytkownicy powinni sami pisać programy dla siebie.",,język wzorców prowadzi projektanta, dostarczając mu działających rozwiązań wszystkich problemów, które mogą powstać w trakcie projektowania. JW to sekwencja fragmentów wiedzy zapisanych w określonym stylu i uporządkowana tak, że naprowadza projektanta na właściwe pytania i odpowiedzi we właściwym czasie." Kent Beck, Ward Cunningham,,Using Pattern Languages for Object-Oriented Programs" 7
Historia, 1994 Wzorzec projektowy identyfikuje i opisuje pewną abstrakcję, której poziom znajduje się powyżej poziomu abstrakcji pojedynczej klasy, instancji lub komponentu. E. Gamma, R. Helm, R. Johnson, J. Vlissides Ponad 30 wznowień w ciągu 10 lat! 8
Wzorce projektowe Wzorce dostarczają gotowych rozwiązań, przez co przyspieszają proces produkcji oprogramowania. Wzorce projektowe stanowią abstrakcyjny opis zależności pomiędzy klasami. Ich wykorzystanie prowadzi do pewnej standaryzacji kodu. Standardowy kod jest pewniejszy, efektywniejszy i łatwiej go zrozumieć. Przez swą ogólność wzorce mogą też zwrócić uwagę na słabości projektu i dostarczyć gotowych rozwiązań problemów, które mogą nie być oczywiste we wczesnym jego stadium (rozszerzanie funkcjonalności, zmiana skali, itp.) Opis wzorców jest też szkołą dobrego programowania. 9
Treść Wprowadzenie: historia, motywacja Katalog wzorców na podstawie klasycznej pozycji Design Patterns, Elements of Reusable OO Software Wzorce kreacyjne Wzorce strukturalne Wzorce behawioralne Podobieństwa wzorców Podsumowanie i wnioski Ćwiczenia 10
Standardowy opis WP (1) Zaproponowany w DP opis WP zawiera rozdziały: Nazwa wzorca projektowego oraz Klasyfikacja Każdy wzorzec powinien posiadać opisową oraz unikalną nazwę, która pomaga w jego rozpoznaniu oraz odwoływaniu się do niego. Wzorzec powinien zostać zakwalifikowany zgodnie z pewnym schematem, np. takim, jak ten zaproponowany w DP. Klasyfikacja ułatwia stosowanie wzorca. Intencja Opis celu, który stoi za wzorcem oraz powody jakimi się należy kierować podczas jego wyboru. Inne nazwy wzorca Wzorzec może mieć więcej niż jedną nazwę, co powinno zostać udokumentowane. 11
Standardowy opis WP (2) Motywacja Scenariusz zawierający problem powiązany z kontekstem, w który wzorzec może być stosowany. Stosowalność Przedstawienie sytuacji, w której wzorzec jest użyteczny reprezentujące jego część związaną z kontekstem. Struktura Graficzna reprezentacja wzorca: zwykle jako schematy UML dotyczące klas oraz interakcji między nimi. Elementy Lista klas i obiektów stosowanych w tym wzorcu oraz opis ich znaczenia. 12
Standardowy opis WP (3) Powiązania Opis wzajemnej interakcji klas i obiektów wykorzystywanych we wzorcu. Konsekwencje Przedstawienie korzyści, skutków ubocznych oraz innych kosztów, które powoduje zastosowanie wzorca. Implementacja Prezentacja implementacji wzorca w wybranym języku. Przedstawienie technik stosowanych podczas praktycznego wykorzystania wzorca, sugestia najlepszej drogi do udanej implementacji. 13
Standardowy opis WP (4) Przykładowy kod Ilustracja jak wzorzec może zostać zastosowany w jednym z języków programowania. Przykłady zastosowania Znane przykłady zastosowania wzorca w rzeczywistych programach. Związane wzorce Odniesienie wzorca do innych, z którymi się wiąże przez wspólne stosowanie, lub wymienną stosowalność oraz przedstawienie różnic w stosunku do podobnych wzorców. 14
Systematyka (DP, 1994) Wzorce kreacyjne abstrakcyjne metody tworzenia obiektów uniezależnienie systemu od sposobu tworzenia obiektów Wzorce strukturalne sposób wiązania obiektów w struktury właściwe wykorzystanie dziedziczenia i kompozycji Wzorce behawioralne algorytmy i przydział odpowiedzialności opis przepływu kontroli i interakcji 15
Katalog wzorców projektowych W DP opisano 23 wzorce: 5 kreacyjnych: Abstract Factory, Builder, Factory Method, Prototype, Singleton 7 strukturalnych: Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy 11 behawioralnych: Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor Katalogi wzorców (np. Portland Pattern Repository http://c2.com/ppr/) są ciągle uzupełniane. Przykład: AbstractFactoryPattern 16
Treść Wprowadzenie: historia, motywacja Katalog wzorców na podstawie klasycznej pozycji Design Patterns, Elements of Reusable OO Software Wzorce kreacyjne Wzorce strukturalne Wzorce behawioralne Podobieństwa wzorców Podsumowanie i wnioski Ćwiczenia 17
Wzorce kreacyjne Abstract Factory (fabryka abstrakcyjna) sposób enkapsulacji grupy fabryk wytwarzających podobne obiekty. Zwykle interfejs implementowany przez konkretne fabryki. Klient nie troszczy się o konkretny rodzaj obiektu, bo używa interfejsów do komunikacji z produktami. (Co zrobić?) Builder (budowniczy) zawiera algorytm tworzenia skomplikowanych obiektów tak, aby klient mógł po prostu zażądać określonego obiektu. Builder jest interfejsem i jednocześnie oddziela proces tworzenia obiektu od jego reprezentacji, aby można było tworzyć podobne obiekty według określonego wzoru. (Jak to zrobić?) Factory Method (metoda wytwórcza) sposób delegacji tworzenia obiektu do podklas tak, aby to one mogły decydować, co dokładnie jest tworzone. Prototype (prototyp) metoda tworzenia obiektów przez klonowanie pewnego obiektu prototypowego. Singleton metoda zapewnienia istnienia pojedynczej instancji danej klasy. 18
Singleton: Nazwa: Singleton Cel: zapewnienie, że wewnątrz danej aplikacji istnieje dokładnie jedna instancja tej klasy. Utworzenie tej instancji i umożliwienie dostępu do niej. Motywacja i stosowalność: czasem potrzebna jest wyłącznie jedna instancja obiektu, którą wywołuje wiele różnych części aplikacji. W takich przypadkach tworzenie obiektu, a następnie niszczenie go (lub pozostawianie do zniszczenia przez gc) jest marnotrawstwem zasobów. 19
Singleton: struktura, uczestnicy, powiązania Singleton jest odpowiedzialny za tworzenie instancji własnej klasy ogranicza dostęp do konstruktora do własnej klasy i podklas (prywatny lub chroniony konstruktor) definiuje statyczną metodę getinstance() udostępniającą instancję klasy 20
Singleton: implementacje: C++ class singleton { private: singleton() { singleton(const singleton &); singleton& operator=(const singleton&); public: string method() { return "sample method"; ~singleton() { static singleton& getinstance() { static singleton instance; return instance; ; 21
Singleton: implementacje: Java public final class Singleton { private final static Singleton singleinstance = new Singleton(); public static Singleton getinstance() { return singleinstance; private Singleton() { public final class Singleton { public final static Singleton singleinstance = new Singleton(); private Singleton() { 22
Singleton: implementacje: Java public class Singleton { private static class Instance { static final Singleton instance = new Singleton(); private Singleton() { public static Singleton getinstance() { return Instance.instance; 23
Singleton: konsekwencje Singleton przejmuje odpowiedzialność za tworzenie instancji własnej klasy Klient nie zarządza instancją klasy; otrzymuje ją na żądanie Singleton może zarządzać także swoimi podklasami Singleton można łatwo rozszerzyć do puli obiektów Singleton zachowuje się podobnie do zmiennej globalnej (antywzorzec!) może powodować zwiększenie liczby powiązań w systemie 24
Abstract Factory: Nazwa: Abstract Factory Cel: hermetyzacja tworzenia obiektów. Motywacja i stosowalność: tworzenie rodzin powiązanych lub zależnych obiektów, udostępnianie biblioteki klas poprzez interfejs, odseparowanie sposobu tworzenia obiektów od sposobu ich używania, ukrywanie specyficznych dla danej platformy szczegółów, zwiększenie rozszerzalności 25
Abstract Factory: struktura 26 wikimedia.org
Abstract Factory: uczestnicy Abstract Factory: definicja interfejsu do tworzenia obiektów implementujących Abstract Product Abstract Poduct: definicja interfejsu, który muszą implementować obiekty tworzone przez fabryki Concrete Factory: implementacja Abstract Factory dostarczająca własnych metod do tworzenia obiektów implementujących interfejsy Abstract Product ConcreteProduct: konkretna implementacja Abstract Product 27
Abstract Factory: przykład (1) 28 apwebco.com
Abstract Factory: przykład (2) // Factories // Abstract: public interface FinancialToolsFactory { public TaxProcessor createtaxprocessor(); public ShipFeeProcessor createshipfeeprocessor(); 29 apwebco.com
Abstract Factory: przykład (3) // Concrete 1 public class CanadaFinancialToolsFactory implements FinancialToolsFactory { public TaxProcessor createtaxprocessor() { return new CanadaTaxProcessor(); public ShipFeeProcessor createshipfeeprocessor() { return new CanadaShipFeeProcessor(); 30 apwebco.com
Abstract Factory: przykład (4) // Concrete 2 public class EuropeFinancialToolsFactory implements FinancialToolsFactory { public TaxProcessor createtaxprocessor() { return new EuropeTaxProcessor(); public ShipFeeProcessor createshipfeeprocessor() { return new EuropeShipFeeProcessor(); 31 apwebco.com
Abstract Factory: przykład (5) // Products public interface ShipFeeProcessor { void calculateshipfee(order order); public interfacetaxprocessor { void calculatetaxes(order order); 32 apwebco.com
Abstract Factory: przykład (6) // Products: Concrete public class EuropeShipFeeProcessor implements ShipFeeProcessor { public void calculateshipfee(order order) { // insert here Europe specific ship fee calculation public class CanadaShipFeeProcessor implements ShipFeeProcessor { public void calculateshipfee(order order) { // insert here Canada specific ship fee calculation 33 apwebco.com
Abstract Factory: przykład (7) // Products: Concrete public class EuropeTaxProcessor implements TaxProcessor { public void calculatetaxes(order order) { // insert here Europe specific taxt calculation public class CanadaTaxProcessor implements TaxProcessor { public void calculatetaxes(order order) { // insert here Canada specific taxt calculation 34 apwebco.com
Abstract Factory: przykład (8) // Client... Customer customer = new Customer(); Order order = new Order(); OrderProcessor orderprocessor = null; FinancialToolsFactory Factory = null; if (countrycode == "EU") { Factory = new EuropeFinancialToolsFactory(); else if (countrycode == "CA") { Factory = new CanadaFinancialToolsFactory(); orderprocessor = new OrderProcessor(Factory); orderprocessor.processorder(order);... 35 apwebco.com
Abstract Factory: konsekwencje Elastyczna konfiguracja rodzaju tworzonych obiektów Uniezależnienie klienta od sposobu tworzenia obiektów Uniezależnienie klienta od konkretnej implementacji obiektów Utrudnienie dodawania kolejnych typów produktów (gdyż wymaga poprawiania wszystkich fabryk) 36
Builder: Nazwa: Builder Cel: odseparowanie procesu konstrukcji złożonych obiektów od ich reprezentacji: ten sam proces konstrukcji może tworzyć różne reprezentacje. Motywacja i stosowalność: tworzenie obiektów przez określanie ich typu i zawartości, odseparowanie procesu tworzenia złożonego obiektu od szczegółów tworzenia skłdowych, oddzielenie kodu tworzącego od reprezentacji 37
Builder: struktura 38 wikimedia.org
Builder: uczestnicy Poduct: typ tworzonych obiektów Builder: definicja interfejsu do tworzenia obiektów implementujących Product Director: zna algorytm realizacji struktury, wykorzystuje obiekty Builder do konstrukcji części i składa te części w całość Concrete Builder: implementacja Abstract Builder dostarczająca własnych metod do tworzenia obiektów Product 39
Builder: przykład (1) // Product class Pizza { private String dough = ""; private String sauce = ""; private String topping = ""; public void setdough (String dough) { this.dough = dough; public void setsauce (String sauce) { this.sauce = sauce; public void settopping (String topping) { this.topping = topping; public String tostring() { return dough + "+" + topping + "+" + sauce; 40 wikipedia.org
Builder: przykład (2) // Abstract Builder abstract class PizzaBuilder { protected Pizza pizza; Składniki algorytmu public Pizza getpizza() { return pizza; public void createnewpizzaproduct() { pizza = new Pizza(); public abstract void builddough(); public abstract void buildsauce(); public abstract void buildtopping(); 41 wikipedia.org
Builder: przykład (3) // Director class Waiter { private PizzaBuilder pizzabuilder; Algorytm public void setpizzabuilder (PizzaBuilder pb) { pizzabuilder = pb; public Pizza getpizza() { return pizzabuilder.getpizza(); public void constructpizza() { pizzabuilder.createnewpizzaproduct(); pizzabuilder.builddough(); pizzabuilder.buildsauce(); pizzabuilder.buildtopping(); 42 wikipedia.org
Builder: przykład (4) // Client class BuilderDemo { public static void main(string[] args) { Waiter waiter = new Waiter(); PizzaBuilder hawaiian_pizzabuilder = new HawaiianPizzaBuilder(); PizzaBuilder spicy_pizzabuilder = new SpicyPizzaBuilder(); waiter.setpizzabuilder ( hawaiian_pizzabuilder ); //waiter.setpizzabuilder ( spicy_pizzabuilder ); waiter.constructpizza(); Pizza pizza = waiter.getpizza(); System.out.println( pizza ); 43 wikipedia.org
Builder: przykład (5) // ConcreteBuilder1 class HawaiianPizzaBuilder extends PizzaBuilder { public void builddough() { pizza.setdough("cross"); public void buildsauce() { pizza.setsauce("mild"); public void buildtopping() { pizza.settopping("ham+pineapple"); // ConcreteBuilder2 class SpicyPizzaBuilder extends PizzaBuilder { public void builddough() { pizza.setdough("pan baked"); public void buildsauce() { pizza.setsauce("hot"); public void buildtopping() { pizza.settopping("pepperoni+salami"); 44 wikipedia.org
Builder: konsekwencje Elastyczna konfiguracja rodzaju tworzonych obiektów Uniezależnienie klienta od sposobu tworzenia obiektów Uniezależnienie klienta od konkretnej implementacji obiektów 45
Builder a AbstractFactory Builder zawiera logikę tworzenia obiektu: opisuje, w jaki sposób tworzymy obiekt, ale chodzi o konkretny obiekt AbstractFactory odwleka decyzję o typie tworzonego obiektu do momentu wykonania, specyfikowany jest tylko interfejs tworzonego obiektu Builder: jak to zrobić? AbstractFactory: co zrobić? 46
Treść Wprowadzenie: historia, motywacja Katalog wzorców na podstawie klasycznej pozycji Design Patterns, Elements of Reusable OO Software Wzorce kreacyjne Wzorce strukturalne Wzorce behawioralne Podobieństwa wzorców Podsumowanie i wnioski Ćwiczenia 47
Wzorce strukturalne Adapter (adapter) dopasowuje obiekt/klasę do wymagań klienta: adaptowany obiekt posiada oczekiwane możliwości, ale ma nieodpowiedni interfejs. Bridge (most) oddzielenie abstrakcji od sposobu implementacji tej abstrakcji przez zastosowanie kompozycji i dziedziczenia Composite (kompozyt) traktowanie kolekcji w taki sam sposób, jak jej składowych Decorator (dekorator) umożliwienie dynamicznego modyfikowania właściwości obiektów (a nie klas) Facade (fasada) uproszczenie dostępu do złożonego fragmentu kodu (uproszczenie interfejsu) Flyweight pozwala oszczędzić zasoby przez efektywne (wspólne) przechowywanie podobnych obiektów. Proxy (pośrednik) pośredni dostęp do obiektu (zdalnego, dużego współdzielonego, wrażliwego). 48
Bridge: cel Oddzielenie (abstrakcji) interfejsu i implementacji w dwóch ortogonalnych hierarchiach, aby mogły ewoluować niezależnie od siebie Podział implementacji w hierarchi 49
Bridge: struktura 50
Bridge: uczestnicy Abstraction definiuje zewnętrzny interfejs Implementor przechowuje implementację, nie jest spokrewniony z Abstraction RefinedAbstraction rozszerza Abstraction zawiera uchwyt do Implementora, który jest inicjowany jako ConcreteImplementor, ale używany jako Implementor ConcreteImplementor implementuje Implementor 51
Bridge: przykład (1) // Abstraction abstract class Shape { abstract void Draw(); abstract void ResizeByPercentage(double pct); protected DrawingAPI drawingapi; // low-level // high-level // Implementor interface DrawingAPI { void DrawCircle(double x, double y, double radius); 52 wikipedia.org
Bridge: przykład (2) // ConcreteImplementor 1/2 class DrawingAPI1 implements DrawingAPI { public void DrawCircle(double x, double y, double radius) { System.out.printf("API1.circle at [%f,%f] radius %f\n", x, y, radius); // ConcreteImplementor 2/2 class DrawingAPI2 implements DrawingAPI { public void DrawCircle(double x, double y, double radius) { System.out.printf("API2.circle at [%f,%f] radius %f\n", x, y, radius); 53 wikipedia.org
Bridge: przykład (3) // Refined Abstraction class CircleShape extends Shape { private double x, y, radius; public CircleShape(double x, double y, double radius, DrawingAPI drawingapi) { this.x = x; this.y = y; this.radius = radius; this.drawingapi = drawingapi; // low-level i.e. Implementation specific public void Draw() { drawingapi.drawcircle(x, y, radius); // high-level i.e. Abstraction specific public void ResizeByPercentage(double pct) { radius *= pct; 54 wikipedia.org
Bridge: przykład (4) // Client class BridgeDemo { public static void main(string[] args) { Shape[] shapes = new Shape[2]; shapes[0] = new CircleShape(1, 2, 3, new DrawingAPI1()); shapes[1] = new CircleShape(5, 7, 11, new DrawingAPI2()); for (Shape shape : shapes) { shape.resizebypercentage(2.5); shape.draw(); 55 wikipedia.org
Bridge: konsekwencje Ortogonalizacja hierarchii Abstraction i Implementor powoduje, że mogą one być rozszerzane niezależnie Implementacja może być współdzielona przez wiele abstrakcji Detale implementacji są ukrywane przed obiektami Client 56
Flyweight: cel Współdzielenie obiektów w celu zmniejszenia zapotrzebowania na pamięć Tworzenie instancji na żądanie Wydzielenie z obiektu stanu wewnętrznego (współdzielonego) i zewnętrznego (specyficznego) 57
Flyweight: struktura, powiązania FlyweightFactory getflyweight(key : String) +flyweights Flyweight operation(extrinsicstate) if (flyweights[key] exists) { return existing flyweight; else { create new one; add to pool; return the new one; ConcreteFlyweight operation(extrinsicstate) UnsharedConcreteFlyweight operation(extrinsicstate) Client 58
Flyweight: uczestnicy Flyweight definiuje interfejs do przyjmowania i odtwarzania stanu zewnętrznego obiektu Concrete Flyweight przechowuje stan wewnętrzny (współdzielony) jest niezależny od kontekstu (z wyjątkiem stanu zewnętrznego) Flyweight Factory tworzy i przechowuje obiekty Flyweight Client otrzymuje obiekty Flyweight za pośrednictwem Flyweight Factory 59
Flyweight: przykład (1) interface GraphicObject { // The Flyweight public void printatposition( int x, int y ); class GraphicChar implements GraphicObject { // ConcreteFlyweight1 char c; String fontface; public GraphicChar(char c, String fontface) { this.c = c; this.fontface = fontface; public void printatposition(int x, int y) { System.out.printf("Printing '%c' in '%s' at position %d:%d.\n", c, fontface, x, y); 60
Flyweight: przykład (2) class Picture implements GraphicObject { // ConcreteFlyweight2 String filename; int width,height; public Picture( String filename, int width, int height ) { this.filename= filename; this.width = width; this.height = height; public void printatposition(int x, int y) { System.out.printf( "Printing '%s' scaled to %dx%d at position %d:%d.\n", filename, width, height, x, y ); 61
Flyweight: przykład (3) class GraphicObjectFactory { HashMap<String, GraphicObject> pool = new HashMap<String, GraphicObject>(); public int getnum() { return pool.size(); public String tostring() {// for testing... public GraphicObject get(character c, String fontface) { GraphicObject go; String key = "C: " + c.tostring() + "@" + fontface; if ((go = pool.get(key)) == null) { go = new GraphicChar(c, fontface); pool.put(key, go ); return go;... 62
Flyweight: przykład (4)... public GraphicObject get(string filename, int width, int height) { GraphicObject go; String key = "P: " + filename + "@" + width + "x" + height; if ((go = pool.get(key)) == null) { go = new Picture(fileName,width,height); pool.put(key, go ); return go; 63
Flyweight: przykład (5) class FlyWeightExample { public static void main(string[] args) { GraphicObjectFactory gof = new GraphicObjectFactory(); ArrayList<GraphicObject> document = new ArrayList<GraphicObject>(); document.add( gof.get("smile.jpg", 100, 100) ); document.add( gof.get(' ', "Times") );... int x=0, y=0; for (GraphicObject c : document) { c.printatposition( x++, y); 64
Flyweight: konsekwencje Zmniejszenie wymagań pamięciowych programu zmniejszenie ogólnej liczby obiektów zmniejszenie rozmiaru stanu obiektów stan zewnętrzny może być przechowywany lub wyliczany Wzrost złożoności obliczeniowej dodatkowy nakład na zarządzanie stanem zewnętrznym 65
Treść Wprowadzenie: historia, motywacja Katalog wzorców na podstawie klasycznej pozycji Design Patterns, Elements of Reusable OO Software Wzorce kreacyjne Wzorce strukturalne Wzorce behawioralne Podobieństwa wzorców Podsumowanie i wnioski Ćwiczenia 66
Wzorce behawioralne (1) Chain of Responsibility (łańcuch odpowiedzialności) oddzielenie (uniezależnienie) nadawcy i odbiorcy zdarzenia. Zarządzanie kolejnością (strukturą) przekazywania żądań. Command (polecenie) realizacja obiektu-polecenia Interpreter realizacja gramatyk specjalizowanych języków i interpreterów tych języków. Iterator nawigacja po kolekcji obiektów bez znajomości wewnętrznej struktury tej kolekcji. Mediator pośrednik między dużą liczbą klas. Obiekt (jedyny) znający wszystkie klasy systemu. Zmniejsza powiązania między klasami. Memento zachowywanie stanu obiektu w celu późniejszego odtworzenia. 67
Wzorce behawioralne (2) Observer (obserwator) zarządzanie jednostronną komunikacją pomiędzy obiektem obserwowanym i (dynamicznie zmienną) listą obiektów obserwujących. State (stan) reprezentacja stanu/zachowania obiektu przez wewnętrzny składnik, który może się dynamicznie zmieniać. Strategy (strategia) delegacja definicji algorytmu do klas rozszerzających interfejs. Template Method (szablon metody) definiowanie szablonu metody w klasie pierwotnej; detale są definiowane w klasach pochodnych Visitor (odwiedzający) odseparowanie algorytmów od struktur danych przez abstrakcję zarówno tych struktur (z punktu widzenia algorytmów), jak i algorytmów (z p. widzenia struktur). 68
Command: cel Rozprzęgnięcie obiektów wykonujących operacje i operacji Hermetyzacja operacji w postaci obiektów (polecenie i argumenty) Umożliwienie parametryzacji klientów obiektami poleceń Wsparcie dla poleceń odwracalnych 69
Command: struktura Client Invoker Command execute() Receiver action() ConcreteCommand state execute() receiver->action() 70
Command: interakcje client : Client invoker : Invoker command : Command new Command() receiver : Receiver storecommand(command) configure(receiver) execute( ) action( ) 71
Command: uczestnicy Command definicja interfejsu obiektu reprezentującego polecenie Concrete Command jest powiązany z właściwym obiektem Receiver implementuje akcję w postaci metody execute() Client tworzy Concrete Command Invoker ustala odbiorcę akcji każdego obiektu Command wywołuje metodę execute() obiektu Command Receiver jest przedmiotem akcji wykonanej przez Command 72
Command: przykład (1) class ExitAction extends AbstractAction { private Component target; public ExitAction(String name, Icon icon, Component t){ putvalue(action.name, name); putvalue(action.small_icon, icon); putvalue(action.short_description, name + " the program"); target = t; public void actionperformed(actionevent evt) { int answer = JoptionPane.showConfirmDialog( target, "Are you sure you want to exit? ", "Confirmation", JoptionPane.YES_NO_OPTION ); if( answer == JoptionPane.YES_NO_OPTION) System.exit(0); 73
Command: przykład (2) class SubmitAction extends AbstractAction { private Component target; public SubmitAction(String name, Icon icon, Component t){ putvalue(action.name, name); putvalue(action.small_icon, icon); putvalue(action.short_description, name + " the program"); target = t; public void actionperformed(actionevent evt) { JOptionPane.showMessageDialog(target, "submit action clicked "); 74
Command: przykład (3)... Action ea = new ExitAction("Exit", null, this); Action sa = new SubmitAction("Submit", null, this);... JPopupMenu pop = new JPopupMenu("PopMenu"); pop.add(sa); pop.add(ea);... JButton subbtn = new JButton(sa); JButton exitbtn = new Jbutton(ea);... 75
Command: konsekwencje Usunięcie powiązania między nadawcą i przedmiotem polecenia Łatwe dodawanie kolejnych obiektów Command Możliwość manipulacji obiektami Command polecenia złożone: wzorzec Composite Polecenia mogą być odwracalne zapamiętanie stanu przez ConcreteCommand wykorzystanie wzorca Memento 76
Memento: cel zachowanie (w celu późniejszego odtworzenia) stanu obiektu, zasada hermetyzacji nie powinna być naruszana 77
Memento: struktura 78
Memento: uczestnicy StatefullComponent potrafi przekazać swój aktualny stan i odtworzyć go na podstawie dostarczonej informacji StateHolder (Memento) przechowuje stan obiektu StatefullComponent 79
Memento: przykład class Memento { int num; Memento(int c) { num = c; int getnum() { return num; java.util.list<integer> list; java.util.list<memento> undo;... list.add(i, new Integer(num)); undo.add(i, new Memento(num)); 80
Memento: konsekwencje zachowanie hermetyzacji obiektu StatefullComponent uproszczenie klienta ewentualnie podwójny interfejs obiektu StateHolder potencjalny wzrost zapotrzebowania na pamięć 81
State: cel wykorzystanie dziedziczenia do elastycznej definicji zachowania obiektu obiekt zmienia swoje zachowanie, gdy zmienia swój wewnętrzny stan: pozorna zmiana klasy obiektu 82
State: struktura Client Context +currentstate State request() 1 handle() currentstate->handle() ConcreteStateA handle() ConcreteStateB handle() Klient kontaktuje się z konkretnymi implementacjami State poprzez Context, który odwołuje się do tych obiektów przez ich nadklasę. 83
State: uczestnicy Context posiada referencję (typu State) do obiektu reprezentującego bieżący stan State definiuje interfejs pozwalający hermetyzować zachowanie związane z każdym stanem Concrete State definiuje własną implementację określającą zachowanie specyficzne dla tego stanu 84
State: przykład (1) abstract class Connection { // State public abstract void open(); public abstract void close(); public abstract void log(); class Accounting extends Connection { // Concrete1 public void open() { System.out.println("open database for accounting"); public void close() { System.out.println("close the database"); public void log() { System.out.println("log activities"); //... 85
State: przykład (2) class Sales extends Connection { // Concrete2 public void open() { System.out.println("open database for sales"); public void close() { System.out.println("close the database"); public void log() { System.out.println("log activities"); public void update() { // 86
State: przykład class Management extends Connection { // Concrete3 public void open() { System.out.println("open database for management"); public void close() { System.out.println("close the database"); public void log() { System.out.println("log activities"); //... 87
State: przykład class Controller { public static Accounting acct; public static Sales sales; public static Management manage; private static Connection current; Controller() { acct = new Accounting(); sales = new Sales(); manage = new Management();... 88
89 State: przykład... public void makeaccountingconnection() { current = acct; public void makesalesconnection() { current = sales; public void makemanagementconnection() { current = manage; public void open() { current.open(); public void close() { current.close(); public void log() { current.log();
State: konsekwencje Kod związany ze jednym stanem jest zapisany w jednym obiekcie uproszczenie i uealastycznienie kodu Zachowanie obiektu nie jest zaszyte w jego implementacji i może się zmieniać w trakcie wykonania programu Łatwo jest dodawać nowe typy zachowań (kolejne podklasy klasy Stan) Zabezpieczenie przed stanem niespójnym możliwość współdzielenia obiektów State obiekty State zwykle definiują tylko zachowanie obiekty State zwykle są bezstanowe (stan może być przechowywany w obiekcie Context) 90
ChainOfResponsibility: cel Usunięcie powiązania pomiędzy nadawcą i odbiorcą żądania Umożliwienie wielu obiektom obsługi żądania 91
ChainOfResponsibility: struktura Client Handler handlerequest() +successor ConcreteHandler1 handlerequest() ConcreteHandler2 handlerequest() Obiekty Handler tworzą najczęściej listę jednokierunkową (łańcuch), wzdłuż której są przekazywane żądania. 92
ChainOfResponsibility: uczestnicy Handler definiuje interfejs do obsługi żądań Concrete Handler obsługuje jeden rodzaj żądania, pozostałe przekazuje do następnika w łańcuchu posiada referencję typu Handler do następnika Client inicjuje przetwarzanie, przekazując żądanie do pierwszego obiektu Handler w łańcuchu 93
ChainOfResponsibility: konsekwencje Ograniczone powiązania Klient i każdy obiekt Handler nie wiedzą, który z pozostałych obiektów Handler obsługuje dany typ żądania nadawca i odbiorca żądania nie mają o sobie żadnej wiedzy Możliwość elastycznego przydziału odpowiedzialności do obiektów Handler Ułatwione testowanie Brak gwarancji obsłużenia żądania 94
Chain of Responsibility: przykład 1 Filter dofilter() Inbox +filterchain Filter1 +next Filter2 +next Filter3 filter(msg : Message) dofilter() dofilter() dofilter() filterchain.dofilter() if (! iseligible()) next.dofilter() Obiekt Inbox wywołuje pierwszy obiekt Filter w łańcuchu. Kolejne filtry przekazują sobie sterowanie 95
Chain of Responsibility: przykład 2 Inbox filters : Set filter(msg : Message) for (f : filters) { if (f.dofilter()) { break; Filter dofilter() Filter1 Filter2 Filter3 dofilter() dofilter() dofilter() Obiekt Inbox wywołuje kolejno obiekty Filter. 96
Decorator: cel Umożliwienie dynamicznego dodawania funkcjonalności do obiektu Stworzenie elastycznej alternatywy dla tworzenia podklas 97
Decorator: struktura Klient wysyła komunikat do obiektu Decorator, który przekazuje go obiektowi ConcreteComponent oraz wykonuje dodatkowe operacje ( dekoracje ) 98
Decorator: uczestnicy AComponent definiuje wspólny interfejs obiektów, które można dekorować ConcreteComponent realizuje podstawową funkcjonalność obiektu Decorator posiada referencję typu Component i do tego obiektu deleguje komunikaty rozszerza funkcjonalność obiektu ConcreteComponent 99
Decorator: interakcje 100 javaworld.com
Decorator: java.io URL url = new URL( args[0] ); BufferedReader ulrin = new BufferedReader( new InputStreamReader( url.openstream()));... Filereader fr = new FileReader(args[1]); BufferedReader filein = new BufferedReader( fr ); LineNumberReader lin = new LineNumberReader( filein );... FileReader filein= new FileReader( args[2] ); StreamTokenizer in= new StreamTokenizer( filein ); 101
Decorator: java.io 102 javaworld.com
Decorator: java.swing JBorderLabel label1 = new JBorderLabel("JLabel Subclass"); BorderDecorator label2 = new BorderDecorator(new JLabel("Decorated JLabel")); BorderDecorator checkbox1 = new BorderDecorator(new JCheckBox("Decorated JCheckBox")); 103 onjava.com
Decorator: konsekwencje Większa elastyczność w przydziale odpowiedzialności niż w przypadku dziedziczenia Możliwość dodawania funkcjonalności w trakcie wykonywania programu, gdy jest ona potrzebna Tożsamość obiektu z którym komunikuje się klient może się zmieniać wskutek dekoracji Łatwiejsze testowanie poszczególnych dekoratorów 104
Visitor: cel Reprezentacja operacji do wykonania na elementach heterogenicznej struktury Realizacja operacji w sposób specyficzny dla typu odwiedzanego elementu Umożliwienie tworzenia nowych operacji bez konieczności modyfikacji klas wewnątrz struktury 105
Visitor: struktura Client Visitor visit(concreteelementa) visit(concreteelementb) ConcreteVisitor١ visit(concreteelementa) visit(concreteelementb) ConcreteVisitor٢ visit(concreteelementa) visit(concreteelementb) ObjectStructure foreach() Element accept(visitor) ConcreteElementA accept(visitor) operationa() ConcreteElementB accept(visitor) operationb() visitor->visit(this) visitor->visit(this) 106
Visitor: interakcje : ObjectStructure : ConcreteElementA : ConcreteElementB : ConcreteVisitor١ accept() visit() operationa( ) accept() visit() operationb( ) 107
Visitor: interakcje class ConcreteElementA extends Element { //... public void accept(avisitor v) { v.visitconcreteelementa(this); //... public void operationa() { //... class ConcreteVisitor1 extends Visitor { public void visitconcreteelementa( ConcreteElementA e ) { e.operationa(); 108
Visitor: uczestnicy Visitor definiuje przeciążone metody dla każdego obiektu ConcreteElement do odwiedzenia Element definiuje metodę accept() przyjmującą obiekt Visitor jako parametr Object Structure posiada iterator pozwalający na dostęp do każdego elementu struktury 109
Visitor: przykład (1) interface Expression { // Element void accept(expressionvisitor v); class IntExp implements Expression { // ConcreteElementA int value; IntExp( int v ) { value = v; public void accept(expressionvisitor v) { v.visitintexp(this); 110
Visitor: przykład (2) class AddExp implements Expression { // ConcreteElementB Expression e1, e2; AddExp( Expression e1, Expression e2 ) { this.e1 = e1; this.e2 = e2; public void accept(expressionvisitor v) { v.visitaddexp(this); 111
Visitor: przykład (3) class MulExp implements Expression { // ConcreteElementC Expression e1, e2; MulExp( Expression e1, Expression e2 ) { this.e1 = e1; this.e2 = e2; public void accept(expressionvisitor v) { v.visitmulexp(this); 112
Visitor: przykład (4) class ExpressionPrinter implements ExpressionVisitor { // ConcreteVisitor public void visitintexp(intexp e) { System.out.print(e.value); public void visitaddexp(addexp e) { e.e1.accept(this); System.out.print(" + "); e.e2.accept(this); public void visitmulexp(mulexp e) { e.e1.accept(this); System.out.print(" * "); e.e2.accept(this); 113
Visitor: przykład (5) public class VisitorDemo { // Client public static void main( String [] args ) { IntExp i1= new IntExp( 1 ); IntExp i2= new IntExp( 2 ); IntExp i3= new IntExp( 3 ); AddExp ae= new AddExp( i1, i2 ); MulExp me= new MulExp( ae, i3 ); ExpressionVisitor visitor = new ExpressionPrinter(); me.accept( visitor ); System.out.println( "" ); 114
Visitor: konsekwencje Możliwość odwiedzenia obiektów niespokrewnionych ze sobą Łatwe dodawanie nowych obiektów Visitor pod warunkiem, że akceptują postać metody visit Utrudnione dodawanie nowych typów Element konieczność modyfikacji klasy Visitor i jej podklas Możliwość zbierania informacji z elementów struktury w sposób dla nich specyficzny Naruszenie hermetyzacji obiektów Visitor i Element obiekty muszą odwoływać się do swoich publicznych metod 115
Treść Wprowadzenie: historia, motywacja Katalog wzorców na podstawie klasycznej pozycji Design Patterns, Elements of Reusable OO Software Wzorce kreacyjne Wzorce strukturalne Wzorce behawioralne Podobieństwa wzorców Podsumowanie i wnioski Ćwiczenia 116
Podsumowanie: podobieństwa i różnice Te wzorce używają relacji "zawiera" Adapter: opakuj obiekt tak, aby dopasowac jego interfejs Facade: opakuj skomplikowany system uproszczonym interfejsem Proxy: opakuj obiekt dodatkową funkcjonalnością 117
Podsumowanie: podobieństwa i różnice Te wzorce używają relacji "dziedziczy" Strategy: zdefiniuj interfejs algorytmu w klasie bazowej i implementuj w podklasach FactoryMethod: zdefiniuj w klasie bazowej metodę zróbobiekt i przeciążaj ją w klasach pochodnych Visitor: stwórz dwie hierarchie, które wzajemnie się obsługują 118
Podsumowanie: podobieństwa i różnice Te wzorce opakowują hierarchię dziedziczenia Builder: hierarchia "budowniczych" State: hierarchia możliwych zachowań Bridge: hierarchia abstrakcji + hierarchie implementacji Observer: hierarchia obserwatorów reagujących na zmiany stanu obiektu obserwowanego 119
Podsumowanie: podobieństwa i różnice Te wzorce reprezentują rekursywne opakowania Composite: traktuj tak samo obiekt i kolekcję Decorator: opakuj opakowanie opakowania Chain of Responsibility: przerzucaj się pracą do wykonania Interpreter: mapuj problem na język, ten na gramatykę, a ją na wzorzec Composite 120
Podsumowanie: podobieństwa i różnice Te wzorce udają, że wszystko jest obiektem Command: polecenie jest obiektem Iterator: iteracja jest interfejsem Mediator: struktura aplikacji jest obiektem Memento: stan obiektu jest obiektem Prototype: operator new można zastąpić metodą obiektu 121
Podsumowanie: podobieństwa i różnice Te wzorce nie pasują gdzie indziej Abstract Factory: hierarchia tworząca hierarchie Template Method: hierarchia metod MediatorFlyweight: oszczędzaj zasoby oddzielając to, co zmienne, od tego, co stałe. Singleton: kontroluj, ile czego masz 122
Treść Wprowadzenie: historia, motywacja Katalog wzorców na podstawie klasycznej pozycji Design Patterns, Elements of Reusable OO Software Wzorce kreacyjne Wzorce strukturalne Wzorce behawioralne Podobieństwa wzorców Podsumowanie i wnioski Ćwiczenia 123
Zakończenie Wzorce nie zostały wymyślone, a jedynie zkatalogowane przez GoF. Wzorce są efektem prac wielu osób. Wzorce są (prawie) gotowymi rozwiązaniami typowych problemów. Wzorce uczą dobrego programowania 124