Sunteți pe pagina 1din 13

Design Patterns

Şabloane de proiectare
3. Şabloane creaţionale
3.5. Prototype

2/18/2020 Design Patterns - 03 05 Prototype 1


3. Şabloane creaţionale
3.1. Introducere
3.2. Factory Method
3.3. Abstract Factory
3.4. Builder
3.5. Prototype
3.6. Singleton
3.7. Concluzii

2/18/2020 Design Patterns - 03 05 Prototype 2


3.5. Prototype
1. pattern name and classification/numele şablonului şi clasificarea: Prototype, obiect
2. intent/scop: specifică tipurile de obiecte care se creează prin folosirea unei instanţe prototip, şi
creează noile obiecte prin copierea acestui prototip.
3. also known as (AKA)/alte nume: nu are
4. motivation/motivaţie: editor pt
partituri muzicale
 cadru general de editor grafic
 obiecte specifice pt note, pauze,
durate
 paletă de instrumente pt gestiunea
obiectelor muzicale pe portativ
 instrumente de selectare, mutare,
manipulare
 clasele Staff, MusicalNote aparţin
soluţiei
 clasa GraphicTool aparţine cadrului
 nu ştie de existenţa claselor soluţiei
 cum se poate parametriza GraphicTool ca să creeze instanţe ale claselor de obiecte din soluţie?
 (I): se derivează din GraphicTool câte o subclasă pt fiecare clasă de obiecte din soluţie
 explozie de subclase care diferă între ele doar prin tipul de obiect instanţiat
 (II): GraphicTool creează o nouă instanţă a lui Graphic prin copierea (clonarea) unei instanţe (prototip) a unei
subclase a lui Graphic
 clasa GraphicTool este parametrizată cu prototipul care trebuie să-l cloneze şi apoi să-l adauge la document
 dacă toate subclasele lui Graphic au o metodă clone(), atunci GraphicTool va putea clona orice tip de obiect Graphic
2/18/2020 Design Patterns - 03 05 Prototype 3
3.5. Prototype
5. applicability/aplicabilitate: şablonul Prototype se foloseşte când sistemul trebuie să fie
independent de modul în care sunt create, compuse şi reprezentate produsele şi
 când clasele ce trebuie instanţiate sunt specificate la execuţie, de exemplu prin încărcare dinamică sau
 se doreşte evitarea construirii unei ierarhii de clase de fabrici care este în paralel cu ierarhia de clase
de produse sau
 când instanţele unei clase pot avea numai una din câteva (puţine) combinaţii diferite de stare.
 de regulă este mai convenabilă instalarea unui număr corespunzător de prototipuri şi clonarea lor decât
instanţierea manuală a claselor, de fiecare dată cu starea corespunzătoare.
6. structure/structură:
7. participants/participanţi:
 Prototype (Graphic): interfaţă ce declară o metodă
pentru clonarea obiectelor
 ConcretePrototype (Staff, WholeNote, HalfNote)
PMWidgetFactory): clase ce implementează operaţiile
de clonare a obiectelor proprii
 Client (GraphicTool): clasă care creează obiecte noi
cerând prototipului să se cloneze
8. collaborations/colaborări:
 Client-ul cere lui Prototype să se cloneze
9. consequences/consecinţe:
 avantajele de la AbstractFactory şi Builder
 ascunde clientului clasele produs concrete, reducând numărul de
nume pe care trebuie să le cunoască
 clientul nu trebuie să modifice clasele specifice aplicaţiei
2/18/2020 Design Patterns - 03 05 Prototype 4
3.5. Prototype
9. consequences/consecinţe:
 avantaje proprii
 (1) adăugarea/ştergerea dinamică a produselor
 clasele produs noi trebuie înregistrate la client - o instanţă prototip a lor
 prototipurile se pot înregistra şi şterge la execuţie
 (2) specificarea de obiecte noi prin modificarea valorilor
 definirea de comportament nou prin compunerea obiectelor (specificarea valorilor pt variabilele de stare), nu prin definirea de
clase noi
 noile obiecte se definesc prin instanţierea claselor existente şi înregistrarea acestora ca prototipuri ale obiectelor client
 clientul poate expune comportament nou prin delegarea responsabilităţilor la prototip
 (3) specificarea de obiecte noi prin modificarea structurii
 obiectele complexe se construiesc din piese şi subansambluri
 circuitele integrate se construiesc din subcircuite
 utilizatorul (clientul) poate defini structuri noi, în care se refolosesc subcircuitele existente
 subcircuitul (circuitul compus) se adaugă ca prototip la o paletă de elemente de circuit disponibile (de bază)
 dacă circuitul compus implementează metoda clone, folosind copierea în adâncime, circuitele cu structură diferită pot fi şie ele prototipuri
 (4) reducerea numărului de subclase
 la Factory Method: ierarhii de clase paralele: Creator şi Product
 la Prototype: nu mai este nevoie de ierarhia de clase Creator (se clonează prototipul în locul apelului de metode fabrică)
 (5) configurarea dinamică cu clase a unei aplicaţii
 fapte: clase Product ce se încarcă dinamic într-o aplicaţie
 aplicaţia care foloseşte instanţe de Product nu poate referi static constructorii acestora
 mediul de execuţie creează câte o instanţă a fiecărei clase, la încărcarea dinamică a acesteia
 instanţa este înregistrată în managerul de prototipuri
 aplicaţia cere managerului de prototipuri să creeze instanţe ale noilor clase, ce nu sunt legate deloc de programul sursă
 dezavantaje
 fiecare subclasă a lui Prototype trebuie să implementeze metoda clone
 este dificilă adăugarea unei metode clone
 la clase existente deja
 când unele variabile de stare nu suportă clonarea
 când în modelul obiect există referinţe circulare

2/18/2020 Design Patterns - 03 05 Prototype 5


3.5. Prototype
10. implementation/implementare: aspecte de discutat
 (1) folosirea unui manager de prototipuri
 fapte
 variantă recomandabilă când numărul de prototipuri din sistem nu este fixat
 constă dintr-o listă ce conţine prototipurile respective
 clienţii memorează/regăsesc prototipurile dorite
 înainte de clonare, clientul cere managerului prototipul dorit
 implementare
 memorie asociativă - listă de perechi (prototip, cheie)
 operaţii
 void register(prototip, cheie)
 void unregister(cheie)
 prototip find(cheie)
 navigare etc
 (2) implementarea operaţiei clone()
 cea mai dificilă
 mai ales când structurile de obiecte conţin referinţe circulare
 dependenţe de limbaj
 Smalltalk: implementare a operaţiei copy moştenită de toate subclasele - copiere la suprafaţă
 C++: constructorul de copiere - implicit copiere la suprafaţă
 Java: metoda Object.clone(), interfaţa Cloneable, constructorul de copiere
 variante de copiere
 copiere la suprafaţă (shallow copy): toate variabilele de instanţă sunt considerate de tipuri valoare
 variabilele obiect sunt partajate între prototip şi clonele acestuia
 copiere în adâncime (deep copy): se clonează variabilele de instanţă de tipuri referinţă
 clona şi prototipul sunt total independente: componentele clonei sunt clone ale componentelor prototipului
 (3) iniţializarea clonelor
 constructor iniţial (fără parametri)
 operaţii setter
 operaţia initialize
 iniţializează starea internă a clonei
2/18/2020 Design Patterns - 03 05 Prototype 6
3.5.
11. sample code/cod sursă exemplu:
Prototype (b)
public class House implements Cloneable {
 soluţia folosind şablonul Prototype // constructor initial
 (a) clasa HousePrototypeFactory public House() {}
 are prototipuri pentru fiecare tip de obiecte // constructor de copiere
care le creează (House, Room, Wall, Door)
public House(House h) { rooms = h.rooms; }
 defineşte metode fabrică pentru obiectele
// initializare
public void initialize() { rooms = new ArrayList();}
House, Room, Wall şi Door // metoda clone
 (b,c) clasele House şi Wall implementează public Object clone() { return new House(this); }
suplimentar constructorul iniţial, de copiere, // celelalte metode
metodele clone şi initialize public void addRoom(Room r) { rooms.add(r);}
(a) public Room roomNo(int no) {
public class HousePrototypeFactory { for (int i = 0; i < rooms.size(); i++) {
public HousePrototypeFactory(House h, Room r = (Room)rooms.get(i);
Wall w, Room r, Door d) { if (r.getRoomNumber() == no)
prototypeHouse = h; return r;
prototypeRoom = r; }
prototypeWall = w; return null;
prototypeDoor = d; }
} public String toString() {
public House makeHouse() { String s = new String("Casa are " + rooms.size() +
House h = (House)prototypeHouse.clone(); " camere \n");
h.initialize(); for (int i=0; i < rooms.size(); i++) {
return h; Room r = (Room)rooms.get(i);
}; s = s + " " + r.toString();
public Room makeRoom(int n) { }
Room r = (Room)prototypeRoom.clone(); return s;
r.initialize(n); }
return r; protected ArrayList rooms;
} }
public Wall makeWall() { (c)
Wall w = (Wall)prototypeWall.clone(); public class Wall extends MapSite implements Cloneable{
w.initialize(); // constructor initial
return w; public Wall() {}
}; // constructor de copiere
public Door makeDoor(Room r1, Room r2) { public Wall(Wall w) {}
Door d = (Door)prototypeDoor.clone(); // initializare
d.initialize(r1, r2, false); public void initialize() {}
return d; // metoda clone
}; public Object clone() { return new Wall(this); }
private House prototypeHouse; // celelalte metode
private Room prototypeRoom; public void Enter() {} ;
private Wall prototypeWall; public String toString() { return "Perete"; }
private Door prototypeDoor; }
} 2/18/2020 Design Patterns - 03 05 Prototype 7
3.5.
11. sample code/cod sursă exemplu:
Prototype
(e)
 soluţia folosind şablonul Prototype public class Room extends MapSite
 (d,e) clasele Door şi Room implementează implements Cloneable {
suplimentar constructorul iniţial, de copiere, // constructor initial
public Room() { }
metodele clone şi initialize // constructor de copiere
(d) public Room (Room r) {
public class Door extends MapSite // copiere de suprafata
this.sides = r.sides;
implements Cloneable{ this.roomNumber = r.getRoomNumber();
// constructor initial };
public Door() {} // initializare
// constructor de copiere public void initialize(int roomNo) {
public Door(Door d) { sides = new MapSite[4];
this.r1 = d.r1; roomNumber = roomNo;
this.r2 = d.r2; }
// metoda clone
this.open= d.getOpen(); public Object clone() {
}; return new Room(this); }
// initializare // celelalte metode de la Ch3.Intro.Room
public void initialize(Room r1, Room r2, public void Enter() {} ;
boolean open) { public MapSite getSide(Direction d) {
this.r1 = r1; return sides[d.getDirection()]; }
this.r2 = r2; public MapSite getSide(int i) {
return sides[i];}
this.open = open; public void setSide(Direction d, MapSite m){
} sides[d.getDirection()] = m; };
// metoda clone public void setSide(int i, MapSite m) {
public Object clone() { sides[i] = m; }
return new Door(this); } public int getRoomNumber() {
// celelalte metode de la Ch3.Intro.Door return roomNumber; }
public void Enter() {} ; public String toString() {
String s = new String("Camera nr. " +
public void setOpen(boolean b) { open = b; } roomNumber + "\n");
public boolean getOpen() { return open; } for (int i=0; i < 4; i++)
public String toString() { s = s.concat(" Directia " +
return "Usa intre camerele " + Direction.DirectionString(i) + " " +
r1.getRoomNumber() + sides[i].toString() + "\n");
" si " + r2.getRoomNumber(); return s;
} }
protected MapSite sides[];
protected Room r1, r2; protected int roomNumber;
protected boolean open; }
}
2/18/2020 Design Patterns - 03 05 Prototype 8
3.5.
11. sample code/cod sursă exemplu:
Prototype (g)
public class BrickHouse extends House {
 soluţia folosind şablonul Prototype // constructor initial
 (f) clasa Client foloseşte numai metodele fabrică public BrickHouse() {}
definite în HousePrototypeFactory // constructor de copiere
 (g,h) subclasele lui House implementează public BrickHouse(BrickHouse h) {
obligatoriu constructorul iniţial, de copiere, rooms = h.rooms; }
metodele clone şi initialize // metoda clone
public Object clone() {
(f) return new BrickHouse(this); }
public class Client { public String toString() {
public static House String s = new String("Casa de caramida are "+
createHouse(HousePrototypeFactory hpf) { rooms.size() + " camere \n");
House aHouse = hpf.makeHouse(); for (int i=0; i < rooms.size(); i++) {
Room r = (Room)rooms.get(i);
Room r1 = hpf.makeRoom(1); s = s + " " + r.toString();
Room r2 = hpf.makeRoom(2); }
Door theDoor = hpf.makeDoor(r1, r2); return s;
aHouse.addRoom(r1); }
aHouse.addRoom(r2); }
r1.setSide(new Direction("North"), (h)
hpf.makeWall()); public class WoodHouse extends House {
r1.setSide(new Direction("East"), theDoor); // constructor initial
r1.setSide(new Direction("South"), public WoodHouse() {}
hpf.makeWall()); // constructor de copiere
r1.setSide(new Direction("West"), public WoodHouse(WoodHouse h) {rooms = h.rooms;}
hpf.makeWall()); // metoda clone
r2.setSide(new Direction("North"), public Object clone() {
hpf.makeWall()); return new WoodHouse(this); }
r2.setSide(new Direction("East"), public String toString() {
hpf.makeWall()); String s = new String("Casa de lemn are " +
r2.setSide(new Direction("South"), rooms.size() + " camere \n");
hpf.makeWall()); for (int i=0; i < rooms.size(); i++) {
r2.setSide(new Direction("West"), theDoor); Room r = (Room)rooms.get(i);
return aHouse; s = s + " " + r.toString();
} }
} return s;
}
}
2/18/2020 Design Patterns - 03 05 Prototype 9
3.5.
11. sample code/cod sursă exemplu:
Prototype (j) public class BrickWall extends Wall {
 soluţia folosind şablonul Prototype // constructor initial
public BrickWall() { }
 (i) subclasele lui Door implementează // constructor de copiere
obligatoriu constructorul iniţial, de copiere, public BrickWall(BrickWall w) { }
metodele clone şi initialize // metoda clone
public Object clone() { return new BrickWall(this); }
 (j,k) subclasele lui Wall implementează public String toString() {return "PereteDeCaramida";}
obligatoriu constructorul iniţial, de copiere, }
metodele clone şi initialize (k)public class WoodWall extends Wall {
// constructor initial
 (l,m,n) clasele Demo instanţiază public WoodWall() {
HousePrototypeFactory cu prototipurile woodType = new String("nuc"); }
adecvate // constructor de copiere
public WoodWall(WoodWall w) {woodType = w.woodType;}
(i)public class WoodDoor extends Door { // initializare
// constructor initial public void initialize(String woodType){
public WoodDoor() {} this.woodType = woodType; }
// constructor de copiere // metoda clone
public WoodDoor(WoodDoor d) { public Object clone() {
this.r1 = d.r1; return new WoodWall(this); }
this.r2 = d.r2; public String getWoodType() {
this.open= d.getOpen(); return woodType; }
}; public String toString() {
// metoda clone return "PereteDeLemn"+(woodType.length() != 0
public Object clone() { ? " de " + woodType : ""); }
return new WoodDoor(this); } private String woodType;
public String toString() { }
return "UsaDeLemn intre camerele " + (m)public class BrickHouseDemo {
r1.getRoomNumber() + public static void main(String[] args){
" si " + r2.getRoomNumber(); HousePrototypeFactory hpf = new
} HousePrototypeFactory(
} new BrickHouse(), new BrickWall(),
(l) public class SimpleHouseDemo { new BrickRoom(), new Door());
public static void main(String[] House h = Client.createHouse(hpf);
args){ TextIO.putln(”BrickHouseDemo vers.Prototype\n");
HousePrototypeFactory hpf = TextIO.putln(h.toString());
new HousePrototypeFactory( } }
new House(), new Wall(), (n)public class WoodHouseDemo {
new Room(), new Door()); public static void main(String[] args){
House h = Client.createHouse(hpf); HousePrototypeFactory hpf =
TextIO.putln("SimpleHouseDemo new HousePrototypeFactory(
versiunea Prototype\n"); new WoodHouse(), new WoodWall(),
TextIO.putln(h.toString()); new WoodRoom(), new WoodDoor());
} ........................................
} 2/18/2020 Design Patterns - 03 05 Prototype 10
3.5. Prototype

2/18/2020 Design Patterns - 03 05 Prototype 11


3.5. Prototype
11. sample code/cod sursă exemplu:
 soluţia folosind şablonul Prototype - observaţii
 clasa HousePrototypeFactory conţine
 prototipurile (instanţe ale claselor House, Room, Wall, Door)
 implementarea metodelor fabrică pentru crearea componentelor din prototipuri
 apelează metodele clone şi initialize
 un constructor parametrizat cu instanţele tuturor tipurilor de prototipuri
 clasele componentelor casei - prototipurile (House, Room, Wall, Door) implementează obligatoriu
 constructorul iniţial: folosit la instanţierea HousePrototypeFactory
 constructorul de copiere: folosit la implementarea metodei clone
 metoda clone: apelată în metodele fabrică de la HousePrototypeFactory
 metoda initialize : apelată în metodele fabrică de la HousePrototypeFactory
 orice subclasă a claselor House, Room, Wall, Door trebuie să implementeze obligatoriu
 constructorii iniţiali şi de copiere
 metoda clone
 clientul (clasa Client, care implementează metoda createHouse) foloseşte (cunoaşte) numai clasa
HousePrototypeFactory şi clasele prototipurilor - clasele de bază ale componentelor casei
 în Client se pot pune alte metode createHouse, pentru alte configuraţii de case
 clasa HousePrototypeFactory nu trebuie extinsă
 programele demo (DemoAll, SimpleHouseDemo, BrickHouseDemo, WoodHouseDemo) o instanţiază cu prototipurile adecvate
de componente
 se pot crea instanţe de HousePrototypeFactory cu orice combinaţii posibile de prototipuri de componente, scriind cod numai în
programul Demo

2/18/2020 Design Patterns - 03 05 Prototype 12


3.5. Prototype
12. known uses/utilizări cunoscute:
 istoric
 Sketchpad: A Man-Machine Graphical Communication System, Ivan Sutherland, PhD Thesis, MIT, 1963
 ThingLab (Constraint-oriented simulation laboratory), A. Borning
 menţionat ca şablon de proiectare de Goldberg şi Robson (Smalltalk-80)
 descris complet de James Coplien (1992)
 exemple
 Etgdb - depanator simbolic sub ET++, ce oferă o interfaţă point-and-click pt diverse depanatoare mod linie de
comandă
 fiecărui depanator îi corespunde o clasă DebuggerAdaptor corespunzătoare
 clasa GdbAdaptor adaptează etgdb la sintaxa comenzilor depanatorului GNU gdb
 clasa SunDbxAdaptor adaptează etgdb la sintaxa comenzilor depanatorului SUN dbx
 Etgdb nu are codificate hard clasele DebuggerAdaptor, ci
 (1) citeşte numele adaptorului curent dintr-o variabilă de mediu,
 (2) caută prototipul cu numele respectiv într-o tabelă globală (repository?)
 (3) clonează prototipul găsit
 Mode composer - biblioteca de tehnici de interacţiune (Shan, 1990)
 memorează prototipurile obiectelor ce suportă diverse tehnici de interacţiune într-o bibliotecă
 orice tehnică de interacţiune creată de Mode composer se poate folosi ca prototip prin plasarea sa în bibliotecă
 Unidraw: A framework for building domain-specific graphical editors (John M. Vlissides, Mark A. Linton, 1990).
 exemplul editorului de partituri muzicale din 3.5.4
13. related patterns/şabloane înrudite:
 AbstractFactory (vezi discuţia de la finalul cap 3)
 se poate folosi împreună cu Prototype - vezi codul sursă
 Prototype se foloseşte frecvent împreună cu Composite şi Decorator
2/18/2020 Design Patterns - 03 05 Prototype 13

S-ar putea să vă placă și