Wzorce Bartosz projektowe Walter Jacek Starzyński, ZETiIS PW 1
Motywacja Motto: dobre projekty mają pewne cechy wspólne. Powtórne wykorzystanie sprawdzonych rozwiązań: 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 i uzyskać wynik do pewnego stopnia sprawdzony 2
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 3
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. 4
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" 5
Ponad 30 wznowień w ciągu 10 lat! 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. Johnson, R. Helm, J. Vlissides 6
Systematyka (GoF, 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 7
Historia, 2003 Na przestrzeni lat widziałem wiele projektów aplikacji dla przedsiębiorstw. Spotykamy w nich regularnie podobne rozwiązania, które nieraz dowiodły swojej skuteczności... M. Fowler 8
Systematyka (Fowler, 2003) Wzorce logiki dziedziny Wzorce architektury źródła danych Wzorce zachowań dla mapowania obiektoworelacyjnego Wzorce struktury dla MO-R Wzorce odwzorowań obiektów i relacyjnych metadanych Wzorce prezentacji Wzorce dystrybucji Wzorce stanu sesji Wzorce współbieżności Wzorce podstawowe 9
Wzorce projektowe Wzorce dostarczają gotowych rozwiązań, przez co przyspieszają proces produkcji. 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. 10
Standardowy opis WP (1) Zaproponowany w DP opis WP zawiera nast. rozdziały: Nazwa wzorca projektowego oraz jego 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órym 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 w postaci schematów UML dotyczących klas oraz interakcji. Elementy Lista klas i obiektów stosowanych w tym wzorcu oraz ich znaczenie (objaśnienie struktury). 12
Standardowy opis WP (3) Powiązania Opis wzajemnej interakcji klas i obiektów wykorzystywanych we wzorcu. Konsekwencje Przedstawienie skutków ubocznych oraz innych kosztów, które powoduje zastosowanie wzorca. Implementacja Prezentuje implementację wzorca w wybranym języku. Przedstawienie technik stosowanych podczas praktycznego wykorzystania wzorca, sugeruje najlepsze 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 Znany 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 można go z nimi zamienić oraz przedstawienie różnic w stosunku do podobnych wzorców. 14
Wzorce projektowe GoF GoF zaproponował 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 Katalog wzorców (Portland Pattern Repository http://c2.com/ppr/) jest ciągle uzupełniany. Przykład: AbstractFactoryPattern 15
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. 16
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). 17
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. 18
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). 19
Singleton: przykład wzorca kreacyjnego 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. 20
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 21
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 22
Singleton: implementacje 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() { 23
Singleton: implementacje public class Singleton { private static class Instance { static final Singleton instance = new Singleton(); private Singleton() { public static Singleton getinstance() { return Instance.instance; 24
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) 25
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 26
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 27
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); 28
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 ); 29
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;... 30
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; 31
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); 32
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 33
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 34
Command: struktura Client Invoker Command execute() Receiver action() ConcreteCommand state execute() receiver->action() 35
Command: interakcje client : Client invoker : Invoker command : Command new Command() receiver : Receiver storecommand(command) configure(receiver) execute( ) action( ) 36
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 37
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); 38
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 "); 39
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);... 40
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 41
ChainOfResponsibility: cel Usunięcie powiązania pomiędzy nadawcą i odbiorcą żądania Umożliwienie wielu obiektom obsługi żądania 42
ChainOfResponsibility: struktura Client Handler handlerequest() +successor ConcreteHandler1 handlerequest() ConcreteHandler2 handlerequest() Obiekty Handler tworzą listę jednokierunkową (łańcuch), wzdłuż której są przekazywane żądania. 43
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 44
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 45
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 46
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. 47
State: cel Cele wykorzystanie dziedziczenia do elastycznej definicji zachowania obiektu pozorna zmiana klasy obiektu 48
State: struktura Client Context +currentstate State request() 1 handle() currentstate->handle() ConcreteStateA handle() ConcreteStateB handle() Stan jest obiektem. Zmiana stanu oznacza zmianę obiektu go reprezentującego. Delegowane do niego metody są wywoływane polimorficznie. 49
State: uczestnicy Context posiada referencję do obiektu reprezentującego bieżący stan State definiuje interfejs pozwalający hermetyzować zachowanie związane z każdym stanem Concrete State definiuje własne metody implementujące zachowanie specyficzne dla tego stanu 50
State: konsekwencje Podział zachowania obiektu wg stanów kod związany ze jednym stanem jest zapisany w jednym obiekcie zmiana stanu jest realizowana przez zmianę obiektu stanu na inny ochrona przed stanem niespójnym możliwość współdzielenia obiektów State obiekty State zwykle definiują tylko zachowanie obiekty State zwykle są bezstanowe 51
State: przykład public class Account { private int balance = 0; private String owner = null; private boolean isopen = false; public Account(String owner, int balance) { this.owner = owner; this.balance = balance; this.isopen = true; public void credit(int amount) { if (isopen) { balance += amount; else { alert("konto nieaktywne!"); 52
State: przykład cd. public interface AccountState { public void credit(account acc, int amount); public class AccountOpen implements AccountState { public void credit(account acc, int amount) { acc.balance += amount; public class AccountClosed implements AccountState { public void credit(account acc, int amount) { alert("the account is closed!"); 53
State: przykład cd. public class Account { private int balance = 0; private String owner = null; private AccountState state = null; public Account(String owner, int balance) { this.owner = owner; this.balance = balance; this.state = new AccountOpen(); public void credit(int amount) { this.state.credit(this, amount); // delegacja public void close() { this.state = new AccountClosed(); 54
Decorator: cel Umożliwienie dynamicznego dodawania funkcjonalności do obiektu Stworzenie elastycznej alternatywy dla tworzenia podklas E. Gamma et al. (1995) 55
Decorator: struktura Component +component operation() ConcreteComponent operation() Decorator operation() component->operation() ConcreteDecoratorA addedstate operation() ConcreteDecoratorB operation() addedbehaviour() decorator->operation() addedbehavior() Klient wysyła komunikat do obiektu Decorator, który przekazuje go obiektowi ConcreteComponent oraz wykonuje dodatkowe operacje ( dekoracje ) 56
Decorator: uczestnicy Component definiuje wspólny interfejs obiektów, które można dekorować Concrete Component realizuje podstawową funkcjonalność obiektu Decorator posiada referencję typu Component i do tego obiektu deleguje komunikaty rozszerza funkcjonalność obiektu ConcreteComponent 57
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 58
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 59
Visitor: struktura Client Visitor visit(concreteelementa) visit(concreteelementb) ConcreteVisitor1 visit(concreteelementa) visit(concreteelementb) ConcreteVisitor2 visit(concreteelementa) visit(concreteelementb) ObjectStructure foreach() Element accept(visitor) ConcreteElementA accept(visitor) operationa() ConcreteElementB accept(visitor) operationb() visitor->visit(this) visitor->visit(this) 60
Visitor: interakcje : ObjectStructure : ConcreteElementA : ConcreteElementB : ConcreteVisitor1 accept() visit() operationa( ) accept() visit() operationb( ) 61
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 62
Visitor: konsekwencje Możliwość odwiedzenia obiektów niespokrewnionych ze sobą Łatwe dodawanie nowych obiektów Visitor 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 63
Visitor: przykład public class Bank { List<BankingProduct> products = new ArrayList<BankingProduct>(); public List<BankingProduct> doreport(report report) { List<BankingProduct> result = new ArrayList<BankingProduct>(); for (BankingProduct product : products) { result.add(product.accept(report)); return result; 64
Visitor: przykład cd. public abstract class BankingProduct { public interface Element { public BankingProduct accept(report report); public class Account extends BankingProduct implements Element { public BankingProduct accept(report report) { if (ispriviliged(report)) { return report.visit(this); return null; public class Credit extends BankingProduct implements Element { public BankingProduct accept(report report) { return report.visit(this); 65
Visitor: przykład cd. public class Over1000Report implements Visitor { public BankingProduct visit(account acc) { if (acc.balance > 1000) return acc; return null; public BankingProduct visit(credit credit) { if (credit.draft > 1000 && credit.isactive()) return credit; return null; public class PassAllReport implements Visitor { public BankingProduct visit(account acc) { return this; public BankingProduct visit(credit credit) { return this; 66
Podsumowanie Wzorce projektowe są gotowymi szablonami rozwiązań typowych problemów projektowych Wzorzec posiada określony zestaw atrybutów Katalog wzorców obiektowych stanowi elementarz projektanta oprogramowania 67