Curs 8ogh/files/ip/curs-08.pdf · 2005. 11. 28. · IP 8 În acest curs • Abstract Factory: ofer...
Transcript of Curs 8ogh/files/ip/curs-08.pdf · 2005. 11. 28. · IP 8 În acest curs • Abstract Factory: ofer...
Ingineria Programării
Curs 8Curs 8
Ovidiu Gheorghieş, [email protected]
Adriana Gheorghieş, [email protected]
Design Patterns
Modele de proiectare
IP8 Bibliografie
Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides.Design Patterns. Elements of Reusable Object-Oriented Software.Addison-Wesley, 1995
Pe scurt GOF = Gang of Four
În română:
Şabloane de proiectare. Elemente de software reutilizabil orientat pe obiecte
Editura Teora, 2002
IP8
“Design patterns capture solutions that have developed and evolved over time”
GOF
IP8 Modele de proiectare - clasificare
• modele structurale: se preocupă de modul în care clasele şi obiectele sunt compuse pentru a forma structuri mai mari
(adapter, bridge, composite, decorator, façade, flyweight, proxy)
• modele comportamentale: se preocupă de algoritmi şi de asignarea responsabilităŃilor între obiecte
(chain of responsibility, command, interpreter, iterator, mediator, memento, observer, state, strategy, template method, visitor)
• modele creaŃionale: abstractizează procesul de instanŃiere
(abstract factory, builder, factory method, prototype, singleton)
IP8 În cursul 7
• Singleton: garantează existenŃa unei singure instanŃe a unei clase. Se asigură o modalitate de a accesa instanŃa respectivă.
• Factory Method: defineşte o interfaŃă pentru crearea unui obiect, dar lasă în sarcina subclaselor alegerea tipului acestuia.
• Strategy: defineşte o familie de algoritmi
• Decorator: asignare de responsabilităŃi în mod dinamic
• Composite: obiecte şi grupuri tratate uniform
• Iterator: oferă o modalitate de a accesa obiecte agregate în mod secvenŃial fără a cunoaşte modul de agregare
• Template Method: se defineşte scheletul unui algoritm într-o metodă, lăsând implementarea paşilor algoritmului în seama subclaselor
IP8 În acest curs
• Abstract Factory: oferă o interfaŃă pentru crearea unei familii de obiecte corelate, fără a specifica explicit clasele acestora.
• Builder: separă construirea unui obiect complex de reprezentarea sa, astfel ca procesul de construire să poată crea diferite reprezentări.
• Proxy: oferă un înlocuitor pentru un obiect, prin care se controlează accesul la acel obiect
• Adapter: converteşte interfaŃa unei clase la interfaŃa pe care clienŃii acesteia o aşteaptă
• Bridge: decuplează o abstracŃiune de implementarea sa astfel încât cele două să poată varia independent
• Mediator: defineşte un obiect care încapsulează modul de interacŃiune al unui set de obiecte; promovează cuplarea slabă
• Observer: defineşte o dependenŃă de tip 1-la-n între obiecte, astfel ca atunci când un obiect se modifică, cele care depind de el sunt notificate şi actualizate automat
• Chain of Responsibility: evită cuplarea emiŃătorului unei cereri de receptorul acesteia dând posibilitatea mai multor obiecte să trateze cererea
IP8 Abstract Factory / Fabrică abstractă
• Scop: Oferă o interfaŃă pentru crearea unei familii de obiecte corelate, fără a specifica explicit clasele acestora.
• MotivaŃie: look-and-feel (pe tablă)• Aplicabilitate
– Sistemul trebuie să fie independent de cum produsele cu care lucrează sunt create
– Sistemul este configurat să lucreze cu mai multe familii de produse
– O familie de produse sunt proiectate să funcŃioneze doar împreună
IP8 Abstract Factory (2)
• Structura
AbstractFactory«interface»
+CreateProductA()+CreateProductB()
ConcreteFactory1
+CreateProductA()+CreateProductB()
ConcreteFactory2
+CreateProductA()+CreateProductB()
Client
AbstractProductA AbstractProductB
ProductA1 ProductA2 ProductB1 ProductB2
IP8 Abstract Factory (java)
abstract class AbstractProductA{public abstract void operationA1();public abstract void operationA2();
}
class ProductA1 extends AbstractProductA{ProductA1(String arg){
System.out.println("Hello "+arg);}// Implement the code herepublic void operationA1() { };public void operationA2() { };
}
class ProductA2 extends AbstractProductA{ProductA2(String arg){
System.out.println("Hello "+arg);}// Implement the code herepublic void operationA1() { };public void operationA2() { };
}
IP8 Abstract Factory (java)
abstract class AbstractProductB{//public abstract void operationB1();//public abstract void operationB2();
}
class ProductB1 extends AbstractProductB{ProductB1(String arg){
System.out.println("Hello "+arg);}// Implement the code here
}
class ProductB2 extends AbstractProductB{ProductB2(String arg){
System.out.println("Hello "+arg);}// Implement the code here
}
IP8 Abstract Factory (java)
abstract class AbstractFactory{abstract AbstractProductA createProductA();abstract AbstractProductB createProductB();
}
class ConcreteFactory1 extends AbstractFactory{AbstractProductA createProductA(){
return new ProductA1("ProductA1");}AbstractProductB createProductB(){
return new ProductB1("ProductB1");}
}
class ConcreteFactory2 extends AbstractFactory{AbstractProductA createProductA(){
return new ProductA2("ProductA2");}AbstractProductB createProductB(){
return new ProductB2("ProductB2");}
}
IP8 Abstract Factory (java)
//Factory creator - an indirect way of instantiating the factories
class FactoryMaker{private static AbstractFactory pf=null;
static AbstractFactory getFactory(String choice){if(choice.equals("a")){
pf=new ConcreteFactory1();}else if(choice.equals("b")){
pf=new ConcreteFactory2();}return pf;
}}
// Client
public class Client{public static void main(String args[]){
AbstractFactory pf=FactoryMaker.getFactory("a");AbstractProductA product=pf.createProductA();//more function calls on product
}}
IP8 Builder
• Scop: Separă construirea unui obiect complex de reprezentarea sa, astfel ca procesul de construire să poată crea diferite reprezentări.
• MotivaŃie: (pagina următoare)• Aplicabilitate
– Algoritmul de creare a unui obiect complex este independent de părŃile care compun efectiv obiectul
– Sistemul trebuie să permită diferite reprezentări pentru obiectele care sunt construite.
IP8 Builder (2)
• MotivaŃie
RTFReader
+Parse()
while (t =get_next_token()) {switch(t.Type)case CHAR: builder->ConvertCharacter(t.asChar); break;case FONT: builder->ConvertFontChange(t.asFont); break;case PARAGRAPH: builder->ConvertParagraph();}
DocumentConverter
+ConvertParagraph( :char)+ConvertFont( :Font)+ConvertParagraph()
AsciiConverter TexConverter HtmlConverter
AsciiDocument TexDocument HtmlDocument
IP8 Builder (3)
• Structura
Director
+Construct()
Builder
+BuildPart()
ConcreteBuilder
+BuildPart()+GetResult()
Productfor all objects in structure builder->BuildPart()
IP8 Builder (java)
//Abstract Builder class abstract class TextConverter{
abstract void convertCharacter(char c); abstract void convertParagraph();
}
// Product class ASCIIText{
public void append(char c){ //Implement the code her e } }
//Concrete Builder class ASCIIConverter extends TextConverter{
ASCIIText asciiTextObj;//resulting product
//converts a character to target representation and appends to the resulting object void convertCharacter(char c){
char asciiChar = new Character(c).charValue();//gets the ascii character asciiTextObj.append(asciiChar);
}
void convertParagraph(){}
ASCIIText getResult(){return asciiTextObj;
}}
IP8 Builder (java)
//This class abstracts the document objectclass Document{
static int value;char token;
public char getNextToken(){//Get the next tokenreturn token;
}}
//Directorclass RTFReader{
private static final char EOF='0'; //Delimitor for E nd of Filefinal char CHAR='c';final char PARA='p';char t;TextConverter builder;
RTFReader(TextConverter obj){builder=obj;
}
void parseRTF(Document doc){while ((t=doc.getNextToken())!= EOF){
switch (t){case CHAR: builder.convertCharacter(t);case PARA: builder.convertParagraph();
}}
}}
IP8 Builder (java)
//Client
public class Client{void createASCIIText(Document doc){
ASCIIConverter asciiBuilder = new ASCIIConverter();RTFReader rtfReader = new RTFReader(asciiBuilder);rtfReader.parseRTF(doc);ASCIIText asciiText = asciiBuilder.getResult();
}
public static void main(String args[]){Client client=new Client();Document doc=new Document();client.createASCIIText(doc);
system.out.println("This is an example of Builder Pattern");
}}
IP8 Proxy / Substitut
• Scop– Oferă un surogat sau înlocuitor pentru un obiect, prin care se
controlează accesul la acel obiect.
• MotivaŃie– Creare/iniŃializare la cerere a obiectelor
• Aplicabilitate– Substitut pentru depărtat, ambasador– Substitut virtual– Substitut protector– ReferinŃă deşteaptă
• Indicator deştept• Încărcarea unui obiect persistent la prima accesare
• Asigurearea exculderii mutuale
IP8 Proxy (2)
• Tipuri de obiecte proxy:– Cache Proxy: salvează resurse memorând
rezultate temporare– Count Proxy: face şi alte operaŃii înainte/după
apelarea subiectului real– Protection Proxy: controlează accesul la obiectul
real– Remote Proxy: reprezentant local al unui obiect
aflat la o altă adresă– Virtual Proxy: creează obiecte la cerere (când
este nevoie de ele)
IP8 Proxy (3)
• Structura
ClientSubject
+Request()
RealSubject
+Request()
Proxy
+Request() realSubject->Request
IP8 Cache Proxy Example (java)
abstract class Generator{public abstract double Get_PI(); public abstract double Get_e();
}
class RealGenerator extends Generator{public RealGenerator(){}
public double Get_PI(){return java.lang.Math.PI;
} public double Get_e(){
return java.lang.Math.E; }
}
IP8 Cache Proxy Example (java)
class CacheProxy extends Generator{RealGenerator realobj=null; double Store=0; int LastAccessed=0;
public CacheProxy(){realobj=new RealGenerator();
}
public double Get_PI(){if(LastAccessed!=1){
Store=realobj.Get_PI(); LastAccessed=1;
} return Store;
}
public double Get_e(){if(LastAccessed!=2){
Store=realobj.Get_e(); LastAccessed=2;
} return Store;
}}
IP8 Cache Proxy Example (java)
public class cache{ public static void main(String args[]){
Generator calc=new CacheProxy(); double d=calc.Get_PI(); d=calc.Get_PI(); d=calc.Get_PI(); d=calc.Get_e(); d=calc.Get_e(); d=calc.Get_PI(); d=calc.Get_e();
} }
IP8 Adapter / Adaptor
• Scop– converteşte interfaŃa unei clase la interfaŃa pe care clienŃii
acesteia o aşteaptă.– permite inter-operabilitatea claselor care altfel nu ar fi
compatibile
• MotivaŃie– O clasă dintr-o bibliotecă, proiectată să fie reutilizabilă, nu este
reutilizabilă din simplul motiv că interfaŃa acesteia nu se potriveşte cu una specifică domeniului în care se doreşte utilizată.
• Aplicabilitate– Se doreşte utilizarea unei clase cu o interfaŃă incompatibilă– Se doreşte crearea unei clase reutilizabile ce colaborează cu
clase neprevăzute– (adaptor de obiecte) Se doreşte folosirea a câtorva subclase, dar
adaptarea prin derivare este nepractică.
IP8 Adapter (2)
• Structura
Client Target
+Request()
Adapter
+Request()
Adaptee
+Specif icRequest()
SpecificRequest()Client Target
+Request()
Adapter
+Request()
Adaptee
+Specif icRequest()
adaptee->SpecificRequest()
Adaptor de clasa
Adaptor de obiecte
IP8 Adapter (java)
//Adaptee Class which is a local classclass CustomerInfo{
private int custId;private float salary;
public float getSalary(int custId){/*Write code here to fetch salary from database */return salary;
}}
//Target class is a remote classinterface IRemoteCustomerInfo extends java.rmi.Remot e{
/* All remote methods throw java.rmi.RemoteExceptio n as part of java RMI requirement. */
public float getSalary(int custId) throws java.rmi.RemoteException;
}
IP8 Adapter (java)
// Adapter class that adapts a local class to a rem ote implementation
public class RemoteCustomerInfoAdapter extends java.rmi.server.UnicastRemoteObjectimplements IRemoteCustomerInfo{
protected CustomerInfo adaptee;
public RemoteCustomerInfoAdapter(CustomerInfo custom erInfo)throws java.rmi.RemoteException{
this.adaptee=adaptee; }
public float getSalary(int custId) throws java.rmi.RemoteException{
return adaptee.getSalary(custId);}
}
IP8 Bridge / Punte
• Scop
– Decuplarea unei abstracŃiuni de implementarea saastfel încât cele două să poată varia independent
IP8 Bridge (2)
MotivaŃie3DShape
+Draw ()
Cube
DirectX OpenGL
Prism Pyramid
CubeDX CubeOGL PrismDX PrismOGL PyramidDX PyramidOGL
IP8 Bridge (4)
• MotivaŃie: arhitectură îmbunătăŃită
3DShape
+Draw()+DrawLine()
Cube Prism Pyramid
3DImplementation
DXImplementation OGLImplementation
DirectX OpenGL
IP8 Bridge (3)
• MotivaŃie– Când o abtracŃiune are câteva implementări
posibile, se foloseşte de obicei moştenirea– Folosirea moştenirii în această situaŃie duce la cod
greu de modificat şi de extins.
– Punerea abstracŃiunilor şi a implementărilor în ierarhii diferite duce la crearea de cod mai uşor de întreŃinut
IP8 Bridge (4)
• Structura
Abstraction
+Operation()
RefinedAbstraction
Implementor
+OperationImpl()
ConcreteImplementorA ConcreteImplementorB
Client
IP8 Bridge (java)
class Implementor{
public void operationImp(){
//Implement code here
}
}
class ConcreteImplementor extends Implementor{
//Override parent method
public void operationImp(){
//Implement the code here
}
}
IP8 Bridge (java)
//Abstraction classabstract class Abstraction{
protected Implementor imp;public void operation(){
//Default implementation is provided here;imp = getImplementor();imp.operationImp();
}
//Implementation is provided by child classes.public abstract Implementor getImplementor();
}
class RefinedAbstraction extends Abstraction{// Do the implementation herepublic Implementor getImplementor(){
imp=new ConcreteImplementor();return imp;
}}
IP8 Bridge (java)
public class Client{
public static void main(String args[]){
Abstraction abs=new RefinedAbstraction();
Implementor imp=abs.getImplementor();
abs.operation();
}
}
IP8 Mediator
• Scop. Defineşte un obiect care încapsulează modul de interacŃiune al unui set de obiecte. Promovează cuplarea slabă.
• MotivaŃie. În aplicaŃiile reale,putem ajunge în situaŃii în carefiecare obiect este legat cufiecare (ceea ce e rău).
IP8 Mediator (2)
• MotivaŃie (2)
ListBox
Button
EntryField
RadioBox
RadioBox
FontDialogDirector
ListBox
Button
EntryFieldRadioBox
RadioBox
IP8 Mediator (3)
• Aplicabilitate– Un set de obiecte interacŃionează într-un mod determinat dar
complicat– Reutilizarea unui obiect este dificilă din cauza cumunicării cu
multe alte obiecte.– Comportamentul distribuit prin multe clase să fie refolosit fără
folosirea excesivă a moştenirii
• Structura Mediator Colleague
ConcreteColleague1 ConcreteColleague2ConcreteMediator
IP8 Mediator (exemplu)
IP8 Mediator (exemplu)
IP8 Mediator (exemplu)
IP8 Mediator (java)
abstract class Colleague {private Mediator aMediator;
public Colleague(Mediator m) {aMediator = m;
}
public void changed() {aMediator.colleagueChanged(this);
}
public Mediator getMediator(){return(aMediator);
}
public abstract void Display();}
IP8 Mediator (java)
class OneColleague extends Colleague {private String text;
public OneColleague(Mediator m, String t){super( m );text = t;
}
public void setText(String text){text = text;
}
public String getSelection(){return text;
}
public void Display(){System.out.println("OneColleague = " + _text);
}}
class NextColleague extends Colleague {// similar implementation here
}
IP8 Mediator (java)
abstract class Mediator {
public abstract void colleagueChanged(Colleague theC hangedColleague);}class ConcreteMediator extends Mediator {
private OneColleague aOneColleague;private NextColleague aNextColleague;
public void colleagueChanged( Colleague theChangedC olleague ){String theChangedColleagueSelection =
((OneColleague)theChangedColleague).getSelection();String aOneCollegueSelection = aOneColleague.getSele ction();if (theChangedColleagueSelection.equals(aOneCollegu eSelection)){
aNextColleague.setText( aOneCollegueSelection );}
}
public void createConcreteMediator(){aOneColleague = new OneColleague(this, "OneColleague ");aNextColleague = new NextColleague(this, "NextCollea gue");
}
IP8 Mediator (java)
public class Client {public static void main(String args[]){
ConcreteMediator aConcreteMediator = new ConcreteMedi ator();aConcreteMediator.createConcreteMediator();
(aConcreteMediator.getOneColleage()).Display();(aConcreteMediator.getNextColleague()).Display();
OneColleague newColleague = new OneColleague(aConcreteMediator, "OneColleague") ;
aConcreteMediator.colleagueChanged((OneColleague)ne wColleague );
(aConcreteMediator.getOneColleage()).Display();(aConcreteMediator.getNextColleague()).Display();
}}
IP8 Observer / Observator
• Scop: defineşte o dependenŃă de tip 1-la-n între obiecte, astfel ca atunci când un obiect se modifică, cele care depind de el sunt notificate şi actualizate automat.
• MotivaŃie
IP8 Observer (2)
• Aplicabilitate– Când o abstracŃiune are două aspecte.
Încapsularea fiecăruia în obiecte diferite permite modificarea şi refolosirea lor independentă.
– Când o schimbare a unui obiect are ca efect schimbări ale altor obiecte, fără a şti de la început câte obiecte sunt în această situaŃie.
– Când se doreşte decuplarea obiectelor notificate de obiectul care se schimbă.
IP8 Observer (3)
• StructuraSubject
+Attach(o:Observer)+Detach(o:Observer)
+Notify()
Observer«interface»
+Update()
ConcreteSubject
-subjectState
+GetState()+SetState()
ConcreteObserver
-observerState
+Update()
subject #1
observerState =subject->GetState()
forall o in observer o->Update()
return subjectState
IP8 Observer (4)
IP8 Observer (5)
IP8 public abstract class Subject {
public abstract void attach(Observer observer);public abstract void detach(Observer observer);public abstract void notify();
}
public class ConcreteSubject extends Subject {private State state;Vector observersVector;
public void attach(Observer observer){ observersVector.addElement(observer);
}public void detach(Observer observer){
observersVector.removeElement(observer);}
public void notify(){java.util.Enumeration enumeration = observersVector. elements ();while (enumeration.hasMoreElements()) {
((Observer)enumeration.nextElement()).update();}
}public void setState(State state) {
this.state = state;notify();
}public State getState() {
return state;}
}
IP8 public interface Observer {
void update();
}
public class ConcreteObserver implements Observer {
ConcreteSubject subject;
public void update(){
// Write your code here
subject.getState();
}
}
IP8
Chain of Responsibility /LanŃ de responsabilităŃi
• Scop:
– evită cuplarea emiŃătorului unei cereri de receptorul acesteia dând posibilitatea mai multor obiecte să trateze cererea. – obiectele sunt înlănŃuite, iar cererea este trimisă de-a lungul lanŃului din obiect în obiect până când un obiect o va trata.
IP8 Chain of Responsibility (2)
• MotivaŃie: help contextual
specific general
bu
toan
e
SaveDialog
PrintDialog
Application
IP8 Chain of Responsibility (3)
HelpHandler
+handleHelp()
handler
Application Widget
handler->handleHelp()
Dialog
Button
+handleHelp()+showHelp()
if (can handle) { showHelp();}else{ handler->handleHelp();}
IP8 Chain of Responsibility (4)
• Structura
Client
Handler
+handleRequest() succesor
ConcreteHandler1 ConcreteHandler2
+handleRequest()
IP8 Chain of Responsibility (5)
• Aplicabilitate– Mai multe obiecte pot trata o cerere, iar obiectul
care o va trata nu este cunoscut a priori, el va fi determinat in mod automat.
– Se doreşte ca cererea să fie făcută unui grup de obiecte fără a specifica în mod explicit receptorul acesteia.
– MulŃimea obiectelor care pot trata cererea trebuie specificată în mod dinamic.
IP8
public abstract class Handler {
private Handler successor = null;public int request = 0;
public void Handler(Handler s, int r) {// set successor for this instance successor = s;
// set the request that this instance is responsibl e for request = r;
}
public void Handler() {this.Handler(null,0);
}
public void SetSuccessor(Handler h) {successor = h;
}
public String HandleRequest(int request) {String returnValue = "";
if (successor != null){returnValue = successor.HandleRequest(request);
}
return returnValue ;}
}
IP8
/* This is a Concrete Handler */public class RequestHandler extends Handler {
String instanceName = "Not set";
public RequestHandler(String name, RequestHandler s, int r){super.Handler(s, r);instanceName = name;
}
public RequestHandler(String name){super();instanceName = name;
}
public String HandleRequest(int request) {String returnValue = "";if (request == this.request) {
returnValue = "Handled by " + this.instanceName;} else {
returnValue = super.HandleRequest(request);}return returnValue;
} }
IP8 Chain of Responsibility (6)