Pobierz prezentację
Pobieranie prezentacji. Proszę czekać
OpublikowałJulian Urbaniak Został zmieniony 9 lat temu
1
WZORCE PROJEKTOWE Języki i Techniki Programowania 7.XI.2003 Joanna Zięba
2
CZYM SĄ WZORCE PROJEKTOWE? „Wzorzec opisuje problem powtarzający się w środowisku naszego systemu i opisuje jego rozwiązanie w taki sposób, że może ono być wykorzystane wielokrotnie i na różne sposoby” (Huston Design Patterns - home.earthlink.net/~huston2/dp/patterns.ht ml)
3
ANALIZA WZORCÓW Należy wiedzieć, gdzie wzorców szukać (literatura, zasoby internetowe itp.), umieć je rozpoznawać w programach innych i wybierać najlepsze do swoich celów. Przy wyborze warto zwrócić uwagę na następujące aspekty zagadnienia: - kontekst (co, gdzie, kiedy...) - warunki wstępne - konsekwencje użycia danego rozwiązania - możliwe alternatywy (inne wzorce lub rezygnacja z ich stosowania na rzecz własnych rozwiązań)
4
KLASYFIKACJA WZORCÓW (konstrukcyjne, strukturalne, behawioralne)
5
WZORCE KONSTRUKCYJNE (creational patterns) Opisują jak obiekt może zostać stworzony. Powinny wyodrębniać szczegóły kreacji obiektów tak aby kod był niezależny od ich typów i nie musiał być zmieniany w miarę pojawiania się nowych rodzajów obiektów. Przykłady: Singleton, Fabryka, Fabryka Abstrakcyjna, Prototyp, Budowniczy
6
SINGLETON (Singleton) Gwarantuje, że dana klasa ma tylko jeden obiekt (instancję) i zapewnić globalny sposób dostępu do tego obiektu. Obiekt stworzony wg tego wzorca może zastąpić zmienną globalną. PODEJŚCIE: Klasę typu Singleton należy uczynić odpowiedzialną za tworzenie, inicjalizację, dostęp i ew. zmiany obiektów. Sam obiekt musi być jej składnikiem typu private static, a funkcja inicjalizacji i dostępu – public static
7
Prosty przykład: class Singleton { private Singleton s; private int i; private Singleton(int x) { i = x; } public static Singleton getReference() { if (s == null) s = new Singleton(2); return s; } public int getValue() { return i; } public void setValue(int x) { i = x; } } Przykład z życia: „prezydent RP” – istnieje tylko co najwyżej jeden, a nazwa jednoznacznie identyfikuje sprawującą urząd osobę.
8
Inne wzorce, jak Fabryka Abstrakcyjna, Budowniczy i Prototyp mogą używać Singletona w swojej implementacji Singletonami są często obiekty typu Fasada (zwykle potrzeba tyko jednej) oraz Stan (powinien przyjmować jedną wartość)
9
FABRYKA (Simple Factory) Wzorzec ten w zależności od dostarczonych danych, zwraca instancję jednej z możliwych klas. Najczęściej zwracane klasy wywodzą się z tej samej klasy podstawowej i mają takie same metody, ale każda z nich wykonuje swoje zadania w inny sposób i jest zoptymalizowana dla innego rodzaju danych. Rozwinięciem tego wzorca jest fabryka polimorficzna – struktura gdzie istnieje klasa - fabryka bazowa i jej różne podklasy – specyficzne fabryki.
10
FABRYKA – SCHEMAT
11
abstract class Shape { public abstract void draw(); public abstract void erase(); public static Shape factory(String type) { if(type.equals("Circle")) return new Circle(); if(type.equals("Square")) return new Square(); throw new RuntimeException( "Bad shape creation: " + type); } } class Circle extends Shape { Circle() {} // Package-access constructor public void draw() { System.out.println("Circle.dra w"); } public void erase() { System.out.println("Circle.era se"); } public class ShapeFactory1 extends TestCase { String shlist[] = { "Circle", "Square", "Square", "Circle", "Circle", "Square" }; List shapes = new ArrayList(); public void test() { Iterator it = Arrays.asList(shlist).iterator (); while(it.hasNext()) shapes.add(Shape.factory((St ring)it.next())); it = shapes.iterator(); while(it.hasNext()) { Shape s = (Shape)it.next(); s.draw(); s.erase(); }
12
FABRYKA ABSTRAKCYJNA (Abstract Factory) Wzorca projektowego Abstract Factory można używać w celu otrzymania jednej z wielu związanych ze sobą klas obiektów, z których każdy może na żądanie zwrócić wiele innych obiektów. Wzorzec ten jest fabryką, która zwraca jedną z wielu grup klas. Można nawet gdy używa się Simple Factory, decydować, którą klasę z tej grupy zwrócić. Można także wykorzystać w implementacji wzorzec Prototype, jeśli często będą tworzone obiekty o bardzo zbliżonych własnościach.
13
FABRYKA ABSTRAKCYJNA – SCHEMAT
14
PROTOTYP (Prototype) W tym wzorcu tworzenie obiektu polega na modyfikacji uprzednio utworzonej kopii pewnego obiektu - prototypu. Zastosowanie tego wzorca jest w szczególności uzasadnione, gdy tworzone obiekty zawiera dużą ilość czasochłonnie stworzonych danych, których tylko mała część jest modyfikowana względem prototypu. Przykład z życia: klonowanie, podział komórki
15
interface Xyz { Xyz cloan(); class Tom implements Xyz { public Xyz cloan() { return new Tom(); } public String toString() { return "ttt"; } } class Dick implements Xyz { public Xyz cloan() { return new Dick(); } public String toString() { return "ddd"; } } class Factory { private java.util.Map prototypes; public Factory(){ prototypes = new java.util.HashMap(); prototypes.put( "tom", new Tom() ); prototypes.put( "dick", new Dick() ); public Xyz makeObject( String s ) { return ((Xyz)prototypes.get(s)).cloan(); } } public static void main( String[] args ) { for (int i=0; i < args.length; i++) System.out.print( (new Factory()). makeObject( args[i] ) + " " );
16
BUDOWNICZY (Builder) Ten wzorzec jest podobny do wzorca Abstrakcyjnej Fabryki, gdyż służy on tworzeniu zbioru obiektów, ale tutaj tworzone obiekty są z sobą powiązane (w szczególności gdy tworzą Kompozyt). Obiekt złożony jest tworzony na podstawie danych wejściowych. Dane te są przetwarzane tak, że kolejne ich części tworzą komponenty, które z kolei mogą służyć wraz z innymi danymi utworzeniu obiektu złożonego.
17
BUDOWNICZY – SCHEMAT
18
WZORCE STRUKTURALNE (structural patterns) Pozwalają łączyć obiekty w większe struktury, mając zastosowanie np. w implementacji złożonego interfejsu użytkownika. Przykłady: Adapter, Most, Kompozyt, Dekorator, Fasada, Waga Piórkowa, Proxy
19
ADAPTER (Adapter) Wzorzec Adapter konwertuje interfejs jednej klasy na interfejs innej klasy. Używamy tego wzorca, jeśli chcemy, żeby dwie niezwiązane ze sobą klasy współpracowały ze sobą w jednym programie. Koncepcja wzorca Adaptera jest bardzo prosta: piszemy klasę, która posiada wymagany interfejs, a następnie zapewniamy jej komunikację z klasą, która ma inny interfejs. Istnieją dwa sposoby realizacji: poprzez dziedziczenie i poprzez kompozycję.
20
ADAPTER – PRZYKŁAD IMPLEMENTACJI package adapter; import junit.framework.*; class Target { public void request() {} } class Adaptee { public void specificRequest() { System.out.println("Adaptee: SpecificRequest"); } class Adapter extends Target { private Adaptee adaptee; public Adapter(Adaptee a) { adaptee = a; } public void request() { adaptee.specificRequest(); } public class SimpleAdapter extends TestCase { Adaptee a = new Adaptee(); Target t = new Adapter(a); public void test() { t.request(); } public static void main(String args[]) { junit.textui.TestRunner.run(Si mpleAdapter.class); }
21
KOMPOZYT (Composite) Wzorzec kompozytu pozwala na jednolite traktowanie komponentów i obiektów z nich złożonych poprzez specyfikację ich wspólnego interfejsu. Przykład z życia: zapis działania matematycznego, składa się ono z liczb, symboli operatorów i nawiasów; także przepis kuchenny, jeśli za komponenty uznamy poszczególne składniki.
22
KOMPOZYT – SCHEMAT
23
Przykład: package composite; import java.util.*; import junit.framework.*; interface Component { void operation(); } class Leaf implements Component { private String name; public Leaf(String name) { this.name = name; } public String toString() { return name; } public void operation() { System.out.println(this); } class Node extends ArrayList implements Component { private String name; public Node(String name) { this.name = name; } public String toString() { return name; } public void operation() { System.out.println(this); for(Iterator it = iterator(); it.hasNext(); ) ((Component)it.next()).operation( ); } public class CompositeStructure extends TestCase { public void test() { Node root = new Node("root"); root.add(new Leaf("Leaf1")); Node c2 = new Node("Node1"); c2.add(new Leaf("Leaf2")); c2.add(new Leaf("Leaf3")); root.add(c2); c2 = new Node("Node2"); c2.add(new Leaf("Leaf4")); c2.add(new Leaf("Leaf5")); root.add(c2); root.operation(); } public static void main(String args[]) { junit.textui.TestRunner.run(Composi teStructure.class); }
24
DEKORATOR (Decorator) Wzorzec ten pozwala na dekorowanie zachowania klasy, czyli zmianę jej funkcjonalności bez potrzeby dziedziczenia, które mogłoby stworzyć zbyt wiele mało elastycznych klas. Najprostsza sytuacja:
25
FASADA (Facade) Często program podczas tworzenia ewoluuje i rośnie stopień jego komplikacji. Możemy zauważyć że oprócz korzyści wzorce mają też ujemną cechę: czasami generują one bardzo wiele dodatkowych klas, przez co trudniej jest zrozumieć działanie programu. Poza tym programy często składają się z szeregu podsystemów, z których każdy posiada swój własny skomplikowany interfejs. Dlatego też warto wprowadzić Fasadę – ujednolicony interfejs do szeregu interfejsów poszczególnych podsystemów.
26
FASADA - SCHEMAT
27
WAGA PIÓRKOWA (Flyweight) Waga Piórkowa ogranicza ilość tworzonych instancji obiektów, przez przeniesienie części danych z stanu obiektu do parametrów metod co umożliwia ich współdzielenie. Takie rozwiązanie wpływa korzystnie na szybkość wykonywania się programu – niekiedy niekontrolowane powstawanie zbyt dużej ilości obiektów spowalnia jego pracę.
28
Przykład: zamknięcie wielu obiektów w jednym (przetwarzanie ich osobno skrajnie nieefektywne z powodu dużej ich ilości) class DataPoint { private static int count = 0; private int id = count++; private int i; private float f; public int getI() { return i; } public void setI(int i) { this.i = i; } public float getF() { return f; } public void setF(float f) { this.f = f; } public String toString() { return "id: " + id + ", i = " + i + ", f = " + f; } public class ManyObjects { static final int size = 1000000; public static void main(String[] args) { DataPoint[] array = new DataPoint[size]; for(int i = 0; i < array.length; i++) array[i] = new DataPoint(); for(int i = 0; i < array.length; i++) { DataPoint dp = array[i]; dp.setI(dp.getI() + 1); dp.setF(47.0f); } System.out.println(array[size -1]); }
29
Rozwiązanie: zamknięcie wszystkich DataPoint w jednym ExternalizedData class ExternalizedData { static final int size = 5000000; static int[] id = new int[size]; static int[] i = new int[size]; static float[] f = new float[size]; static { for(int i = 0; i < size; i++) id[i] = i; } class FlyPoint { private FlyPoint() {} public static int getI(int obnum) { return ExternalizedData.i[obnum]; } public static void setI(int obnum, int i) { ExternalizedData.i[obnum] = i; } public static float getF(int obnum) { return ExternalizedData.f[obnum]; } public static void setF(int obnum, float f) { ExternalizedData.f[obnum] = f; } public static String str(int obnum) { return "id: " + ExternalizedData.id[obnum] + ", i = " + ExternalizedData.i[obnum] + ", f = " + ExternalizedData.f[obnum]; } public class FlyWeightObjects { public static void main(String[] args) { for(int i = 0; i < ExternalizedData.size; i++) { FlyPoint.setI(i, FlyPoint.getI(i) + 1); FlyPoint.setF(i, 47.0f); } System.out.println( FlyPoint.str(ExternalizedData.size -1)); }
30
WZORCE OPERACYJNE (behavioral patterns) pomagają zdefiniować komunikację pomiędzy obiektami oraz kontrolować przepływ danych w złożonym programie. Przykłady: Iterator, Łańcuch Odpowiedzialności, Interpreter, Stan, Mediator, Obserwator, Memento, Strategia
31
STAN (State) Wzorzec Stan pozwala obiektowi zmienić zachowanie gdy zmieni się jego stan wewnętrzny.
32
Przykład (bajkowy :-)) //: state:KissingPrincess.java package state; import junit.framework.*; class Creature { private boolean isFrog = true; public void greet() { if(isFrog) System.out.println("Ribbet!"); else System.out.println("Darling!"); } public void kiss() { isFrog = false; } } public class KissingPrincess extends TestCase { Creature creature = new Creature(); public void test() { creature.greet(); creature.kiss(); creature.greet(); } public static void main(String args[]) { junit.textui.TestRunner.run(Ki ssingPrincess.class); }
33
OBSERWATOR (Observer) Wzorzec ma na celu zdefiniowanie zależności miedzy obiektami typu jeden-do-wielu tak, aby przy zmianie stanu jednego pozostałe były o tym powiadamiane i też zmieniały swój stan.
34
ITERATOR (Iterator) Wzorzec Iteratora jest jednym z prostszych i najczęściej wykorzystywanych. Pozwala przemieszczać się poprzez listę lub dowolną kolejkę danych, z wykorzystaniem standardowego interfejsu, bez potrzeby znajomości wewnętrznej reprezentacji danych. Można też zdefiniować specjalne iteratory, które dokonują specjalnego przetwarzania i zwracają tylko niektóre elementy kolekcji danych.
35
Przykład użycia: public class TypedIterator implements Iterator { private Iterator imp; private Class type; public TypedIterator(Iterator it, Class type) { imp = it; this.type = type; } public boolean hasNext() { return imp.hasNext(); } public void remove() { imp.remove(); } public Object next() { Object obj = imp.next(); if(!type.isInstance(obj)) throw new ClassCastException( "TypedIterator for type " + type + " encountered type: " + obj.getClass()); return obj; }
36
Schemat innego zastosowania (C++) class ListIterator { public: ListIterator(const List& alist); virtual ~ListIterator() {} int AtEnd() const; void Restart(); int getPosition()const {return position;} protected: virtual ListElement* get(); virtual ListIterator& advance(); ListIterator& operator=(const ListIterator& other); ListIterator& operator=(const List& alist); private: ListElement* start; ListElement* cursor; int position; }; class ObjectListIterator:public ListIterator { public: ObjectListIterator(const ObjectList& alist); virtual ~ObjectListIterator() {} virtual ObjectListIterator& operator++(); //advances a cursor virtual ObjectListIterator& operator++(int); //same Object* Get(); //gets a pointer to an object void Set(Object*newobj=0); //sets a pointer to an object ObjectListIterator&operator=(const ObjectList& alist); };
37
WZORCE - KORZYŚCI + Sukces jest ważniejszy niż tworzenie wszędzie czegoś nowego + Dobrze napisane wzorce ułatwiają komunikację między autorami kodu + Pochodzą z praktycznego doświadczenia i rozwiązują konkretne problemy + Wzorce wcale nie służą eliminacji programistów!
38
ŹRÓDŁA I BIBLIOGRAFIA Gamma i inni (GoF): „Elements of Reusable Object-Oriented Software” James William Cooper „Java. Wzorce projektowe” (wyd. Helion) Bruce Eckel „Thinking in Patterns”, dostępne na www.bruceeckel.comwww.bruceeckel.com Żródła internetowe – m.in. tutoriale na www.ibm.com (Java Patterns 101 i 201) www.ibm.com
39
MOTTO „Użycie wzorców projektowych pozwala nam uczyć się na sukcesach innych zamiast na własnych błędach”
Podobne prezentacje
© 2024 SlidePlayer.pl Inc.
All rights reserved.