curs 6 modele de proiectare
TRANSCRIPT
Curs 6
They really need more design patterns
Definiţia termenului patternConform dicţionarului Merriam-Webster
termenul de pattern înseamnă
1. o formă sau model propus pentru imitare
2. ceva proiectat sau folosit ca model pentru a face lucruri (calapodul croitorului)
3. o formă sau proiect
4. o configuraţie de evenimente
5. ruta prestabilită a unui avion
6. model comportamental
Are ca sinonim indicat termenul de model2
Termenul a apărut în cadrul studiilor realizate de arhitectul Christopher Alexander care căuta noi maniere pentru a proiecta clădiri şi zone urbane.
El spune că fiecare formă este o regulă cu trei părţi care explică relaţiile existente în cadrul unui anume context, problemă sau soluţie.
Astfel o definiţie curentă este “soluţia unei probleme într-un context”.
Aceste modele pot fi aplicate în diferite activităţi umane inclusiv în dezvoltarea programelor.
3
Istoricul
În 1987 Cunningham şi Beck au pornit de la idea lui Alexandru şi au dezvoltat un minilimbaj orientat pe modele pentru Smalltalk
În 1990 Gaşca celor patru – G4(Gamma, Helm, Johnson and Vlissides) a început scrierea unui catalog ce conţine astfel de modele de programe
1995 G4 publică cartea ce conţine experienţa lor în modele de proiectare
4
Riehle şi Zullighoven menţionează trei tipuri de modele software
Model conceptual
Model de proiectare
Model de programare
5
Modelele de proiectare se pot aplica la mai multe nivele de abstractizare
model complex
soluţia la o problemă generală (tratate de G4)
Proiectarea unei clase care poate fi reutilizată
6
În general, un model are 4 elemente esenţiale:
Numele:
Problema:
Soluţia:
Consecinţele r
7
Categorii de design Pattern din GoF
8
Scop
Creaţional Structural Comportamental
Domeniu
Clasă Fabrica Method Adapter (clasă) InterpreterTemplate Method
Obiect
Abstract FabricaBuilderPrototypeSingleton
Adapter (obiect)BridgeCompositeDecoratorFacadeFlyweightProxy
Chain of Responsibility
CommandIteratorMediatorMementoObserverStateStrategyVisitor
Relatii intre patter-urile din GoF
10
Clase abstracte si concrete
Clasa client participanta Clasa client implicita
Relatii intre clase
Comentariu in pseudocod
11
12
Avantajele folosirii modelelor de proiectare
Capturarea unei experienţe
Facilitează comunicarea între dezvoltatori
Face mai simplă reutilizarea unor modele
Uşurează modificările în proiect
îmbunătăţeşte lizibilitatea proiectului
13
Modele creationale
Abstractizeaza instantierea unui proces.
Exista doua caracteristici dominante
se incapsuleaza cunostiintele despreclasele concrete folosite de sistem
se ascunde maniera in care aceste clasesunt create si cooperarea lor
Fabrica de obiecte
Să se proiecteze o formă de citire a datelor care să primească un nume complet şi să-l împartă automat în nume şi prenume considerând virgula separator.
15
Class Nume
{ protected string prim;
protected string ultim;
public String IaPrim()
{ return prim; }
public String IaUltim()
{ return ultim; } }
Class SeparPrinSpatiu extends Nume
{ public SeparPrinSpatiu(s)
int i=s.lastIndexOf(“ ”);
if(i>0)
{ prim=s.substring(0,i).trim();
ultim=s.substring(i+1).trim(); }
else
{ prim=“”; last=s; } }
Class SeparPrinVirgula extendsNume
{ public SeparPrinVirgula(s)
int i=s.lastIndexOf(“,”);
if(i>0)
{ prim=s.substring(0,i).trim();
ultim=s.substring(i+1).trim(); }
else
{ prim=“”; last=s; }
}
16
class FabricaDeNume
{ public Nume DaNume(String SIn)
{ int i=Sin.indexOf(“,”);
if(i>0)
return newSeparPrinVirgula(SIn);
else
return new SeparPrinSpatiu(SIn);
}
}
În aceste condiţii folosirea este extrem de naturală:
….
FabricaDeNume NumeGen = newFabricaDeNume();//creez un obiect
. . . .
Private void CalculNume()
{
nume=NumeGen.DaNume(entryField.getText()); // citim numele dintr-o cutie de dialog cu utlizatorul
txPrimNume.setText(nume.IaPrim());
// afisăm în cutie primul nume
txUltimNume.setText(nume.IaUltim());// afisăm în cutie al doilea nume
}
17
Fabrica de obiecte - Când? De obicei această tehnică este proiectată atunci
când:
clasa nu poate anticipa ce tipuri de clase de obiecte trebuie să creeze
…
De asemenea mai există o serie de situaţii în care poate fi folosită această abordare
clasa de bază este abstractă iar modelul trebuie să întoarcă o clasă complet funcţională
clasa de bază conţine numai metode implicite şi se va deriva numai atunci când acestea nu sunt suficiente
… 18
Modelul fabrică abstractă O aplicaţie tipică a fabricii abstracte este atunci
când sistemul necesită interfeţe utilizator multiple cum ar fi în Win sau McIntosh.
În această situaţie i se spune fabricii cum se va dori să arate programul din punct de vedere al temei grafice (butoanele, ferestre etc) (de ex Win) şi el va întoarce o fabrica GUI care la rândul ei va trimite obiectele grafice ce se conformează standardului Win.
19
Look and feelString laf = UIManager.getSystemLookAndFeelClassName();
try {
UIManager.setLookAndFeel(laf);
}
catch (UnsupportedLookAndFeelException exc)
{
System.err.println("UnsupportedL&F: " + laf);
}
catch (Exception exc)
{
System.err.println("Error loading " + laf);
}
21
Exemplu Fabrica Abstracta
Exemplu Forma<<Interface>>
Patrat Cerc
<<creates>>
Exemplu Fabrica Abstracta
Forma<<Interface>>
Patrat Cerc
ImplementareFabricaForme
<<creates>>
Exemplu
FabricaForme<<Interface>>
makePatrat()makeCerc()
Exemplu Fabrica Abstracta
public interface FabricaForme {public Forma make (String FormaName) throws Exception
}public class ImplementareFabricaForme implements FabricaForme {
public Forma make(String FormaName) throws Exception {
if (FormaName.equals("Cerc")) return new Cerc();
else if (FormaName.equals("Patrat")) return new Patrat();
else throw new Exception("FabricaForme cannot create " + FormaName);
}
}………………………
private FabricaForme Fabrica;
Fabrica = new ImplementareFabricaForme();Forma s = Fabrica.make("Cerc");
Codul Rezultat
Exemplu Fabrica Abstracta
Metode fabrica
Structura
Modele structurale Descriu modalitatea de combinarea a claselor si
obiectelor pentru a putea forma structuri complexe.
Diferenta dintre modelele pentru clase si cele pentru obiecte se refera la faptul ca primele descriu
Maniera
Maniera
27
Modelul Adaptor Uneori o librărie sau un toolkit nu poate fi folosit
deoarece interfaţa este incompatibilă.
Nu se poate schimba interfaţa unei librării deoarece nu am acces la cod.
Chiar dacă există accesul la sursă nu este eficientă modificarea librăriei pentru fiecare nouă aplicaţie care se dezvoltă.
Un adaptor se foloseste:
…
28
Observatii de implementare Cit de mult trebuie aplicata metoda
o simpla conversie la nivel de interfata
seturi diferite de operatii
Mai este cunoscut si ca wrapper
Exista doua tipuri:
Pt clase
Pt obiecte
29
Un adaptor poate oferi o si dualitate
Un adaptor cu doua cai ofera atat interfata de Adaptare cit si interfata tinta.
Se observa ca avem un client care apeleaza adaptorul care la rindul lui apeleaza entitatea care a fost “Adaptata” aceasta isi indeplineste scopul si eventuale rezultate se intorc pe calea inversa
30
Exemplu Lamapa de birou
Switch
Light
+turnOn+turnOff
Lampa birou simpla
Ce este gresit la aceasta abordare
DIP (Dependency-Inversion Principle)
OCP (Open-Closed Principle )
Exemplu Lamapa de birou
Switch
Light
+turnOn+turnOff
O abordare gresita in extinderea
clasei Switch - DIP
FanSwitch
Fan
+turnOn+turnOff
Switch
<<Interface>>
Switchable+turnOn+turnOff
Light
+turnOn+turnOff
Solutia cu server Abstract
(DIP si OCP sunt OK)
(SRP) Single-Responsibility Principle
Solutia cu un ADAPTOR
Switch
<<Interface>>
Switchable+turnOn+turnOff
Light Adapter
+turnOn+turnOff
Light
+turnOn+turnOff
<<delegates>>
Solutia cu o clasa din ADAPTER
Switch
<<Interface>>
Switchable+turnOn+turnOff
Light Adapter
+turnOn+turnOff
Light
+turnOn+turnOff
Adaptor la nivel de interfata (Java)
Adaptor la nivel de clasa (CPP)
Adaptor cu delegare si mostenire
Adaptor - ExempluClient Code:
Adaptee a = new Adaptee(); Target t = new Adapter(a);
public void test() { t.request(); }
Target Code:class Target {
public void request() {}
}
Adaptee Code:
class Adaptee{
public void specificRequest() {System.out.println("Adaptee: SpecificRequest"); }
}
Adapter Code:class Adapter extends Target{private Adaptee adaptee;public Adapter(Adaptee a)
{ adaptee = a;}public void request()
{ adaptee.specificRequest();}}
Obiect Adaptor
Enumeration
hasMoreElements()
nextElement()
<<Interface>>ServicesEnumeration
hasMoreElements()
nextElement()
RegiteredServices
numServices()
getService()
-adaptee
Client
Obiect Adaptor
public class ServicesEnumeration implements Enumeration {public boolean hasMoreElements() {return this.currentServiceIdx <= adaptee.numServices();}
public Object nextElement() {if (!this.hasMoreElements())
{ throw new NoSuchElementException();}return adaptee.getService(this.currentSerrviceIdx++);
}}
Adaptor – Exemplu Modem<<Interface>>
Modem
+dial+hangup+send+receive
Hayes Modem
Robotics Modem
Ernie’s Modem
Modem ClientsModem Clients
Problema:
Sa presupunem ca sunt sute de clienti modem care vor folosi interfata Modem.
Sa mai presupunem ca acestora li s-a livrat un nou tip de modem (dedicat -Ded) care nu i se mai da numarul .
Sunt o serie de aplicatii noi care folosesc acest tip de modem si nu se obosesc sa faca numarul.
Toti clientii modem trebuie sa fie capabili sa foloseasca acestemodemuri dedicate fara a-si modifica aplicatia.
Adaptor – Exemplu Modem
Solutia ideala a problemei modemului
<<Interface>>
Dialler+dial+hangup
Hayes Modem
Robotics Modem
Ernie’s Modem
Modem ClientsModem Clients
<<Interface>>
Modem+send+receive
Ded Users
Dedicated Modem
Adaptor – Exemplu Modem
Rezolvarea cu ADAPTER
<<Interface>>
Modem
+dial+hangup+send+receive
Hayes Modem
Robotics Modem
Ernie’s Modem
Modem ClientsModem Clients
Dedicated Modem Adapter
DedicatedModem
+send+receive
Ded UsersDed Users<<delegates>>
Bridge
Decupleaza o abstractizare de implementarea ei astfelincat cele doua por varia indepemdent
43
Bridge – exemplu Modem
Modem
DialModem DedicatedModem
Hayes Dial Modem
USR Dial Modem
Ernies Dial Modem
Hayes Dedicated Modem
USR Dedicated Modem
Ernies Dedicated Modem
Bridge Pattern – Modem example<<interface>>ModemImplementation
+dial+hangup+send+receive
Hayes Modem
USR Modem
Ernies Modem
Modem ClientsModem Clients
<<Interface>>
Modem
+send+receive
Ded UsersDed Users
<<Interface>>
Modem
+dial+hangup+send+receive
ModemConnectionController
#dialImp#hangupImp#sendImp#receiveImp+dial+hangup+send+receive
DedModemController
+dial+hangup+send+receive
DialModemController
+dial+hangup+send+receive
<<delegates>>
Dial si Hangup sunt implementatepentrua simula starea conexiunii. Send si Receive deleaga catreimplementarile lor
TOATE metodeledeleaga catreimplementarile lor
Bridge
Car
Ford Toyota Sporty Truck
SportyFord ToyotaTruck FordTruck SportyToyota
Bridge
Ford ToyotaSporty Truck
Car CarManufacturer
Bridge
Bridge Pattern - exampleClient Code:public void test1() { ClientService1 cs1 = new ClientService1(new Implementation1());
cs1.serviceA(); cs1.serviceB(); }public void test2() { ClientService1 cs1 = new ClientService1(new Implementation2());
cs1.serviceA(); cs1.serviceB(); }public void test3() { ClientService2 cs2 = new ClientService2(new Implementation1());
cs2.serviceC(); cs2.serviceD(); cs2.serviceE();}}
Abstraction Code:class Abstraction {
private Implementation implementation;public Abstraction(Implementation imp) { implementation = imp;}public void service1() {implementation.facility1(); implementation.facility2(); }public void service2() {implementation.facility2(); implementation.facility3(); }public void service3() {implementation.facility1(); implementation.facility2();
implementation.facility4();}protected Implementation getImplementation() {return implementation;}
}class ClientService1 extends Abstraction {
public ClientService1(Implementation imp) { super(imp); }public void serviceA() {service1(); service2();} public void serviceB() {service3();}}
class ClientService2 extends Abstraction {public ClientService2(Implementation imp) { super(imp); }public void serviceC() {service2(); service3();} public void serviceD() {service1(); service3();}public void serviceE() {getImplementation().facility3();}}
Bridge Pattern - exampleImplementation Code:interface Implementation { void facility1(); void facility2(); void facility3(); void facility4();}
class Library1 { public void method1() {System.out.println("Library1.method1()");}public void method2() {System.out.println("Library1.method2()"); }}
class Library2 {public void operation1() {System.out.println("Library2.operation1()");}public void operation2() {System.out.println("Library2.operation2()");}public void operation3() {System.out.println("Library2.operation3()");}}
class Implementation1 implements Implementation {private Library1 delegate = new Library1();public void facility1() {System.out.println("Implementation1.facility1"); delegate.method1(); }public void facility2() {System.out.println("Implementation1.facility2"); delegate.method2(); }public void facility3() {System.out.println("Implementation1.facility3");
delegate.method2(); delegate.method1();}public void facility4() {System.out.println("Implementation1.facility4"); delegate.method1();}
}class Implementation2 implements Implementation {private Library2 delegate = new Library2();public void facility1() {System.out.println("Implementation2.facility1");delegate.operation1();}public void facility2() {System.out.println("Implementation2.facility2");delegate.operation2();}public void facility3() {System.out.println("Implementation2.facility3");delegate.operation3();}public void facility4() {System.out.println("Implementation2.facility4");delegate.operation1();}
}
Composite Exemplu
: Assembly
: Part
: CatalogueEntry
name = “screw”
O ierarhie de asamblare
: Part
: Part
: CatalogueEntry
name = “strut”
: Assembly
Contains Contains
Contains Contains
Problema:
Composite
Component
+ cost() : double
0..1
n
Part
+ cost() : double
Assembly
+ cost() : double
Solutie:
Compositepublic abstract class Component
{ public abstract double cost () ; }public class Part extends Component
{ public double cost ()
{ return entry.getCost(); }}public class Assembly extends Component
{ private Vector components = new Vector();public double cost()
{ double total = 0.0; Enumeration enum = components. elements();while (enum.hasMoreElements())
{ total += ((Component)enum.nextElement()).cost();}return total;
} }
Composite
Facade
Arhitectura deschisa
Arhitectura inchisa
Un exemplu de apel
public class HotelBooker{ public ArrayList<Hotel> getHotelNamesFor(Date from, Date to)
{//returns hotels available in the particular date range}} public class FlightBooker{ public ArrayList<Flight> getFlightsFor(Date from, Date to)
{//returns flights available in the particular date range}}
58
public class TravelFacade{
private HotelBooker hotelBooker;private FlightBooker flightBooker; public void getFlightsAndHotels(Date from, Data to)
{
ArrayList<Flight> flights = flightBooker.getFlightsFor(from, to);ArrayList<Hotel> hotels = hotelBooker.getHotelsFor(from, to);//process and return}
}
public class Client{public static void main(String[] args)
{TravelFacade facade = new TravelFacade(); facade.getFlightsAndHotels(from, to);}
} 59
Sabloane comportamentale Se ocupa de descrierea modelelor de comunicare intre
clase.
De fapt descriu fluxul complet de control al unei aplicatii.
Ele se folosesc de obieci mostenirea pentru cazul in care se plica claselor si compuenrea obiectelor in cealalta situatie.
60
Modelul Lant de responsabilitati Acesta evita cuplarea intre expeditorul si destinatarul unei
cereri acordând mai multor obiecte posibilitatea de a rezolva cerea.
Un exemplu de aplicație in care se poate folosi ar fi realizarea unei componente de asistenta sensibila la context pentru o interfața grafica cu utilizatorul unde utilizatorul poate obține informația suplimentara din orice zona a interfeței grafice printr-un simplu click.
Cea mai buna abordare ar fi organizarea informației suplimentare de ajutor in acord cu nivelul ei de generalitate
Apare problema ca obiectul care va raspunde la cererea de ajutor nu este explicit cunoscut de catre obiectul din interfata grafica (buton cutie de dialog etc) care initiazarespectiva cerere.
61
Sa presupunem ca utilizatorul cere asistenta din zona unui buton marcat ca print.
62
Pentru a putea transmite cererea in maniera de mai sus fiecare obiect trebuie sa partajeze o interfata comuna folosita fie pentru rezolvarea cererilor fie pentru accesarea succesorului din lant.
Exista componentele normale si o clasa mixin care permite crearea claselor widget care isi pot desena priopriile margini.
Acealasi efect poate fi obtinut si prin adaugarea de comportamente suplimentare la clasele mostenite
63
64
Unde o structura tipica de inlantuire de obiecte ar arata
65
La implementarea lantului de succesori avem doua posibilitati
Definirea de noi legaturi atat la nivelul clasei Handlersau la nivelul ConcreteHandler
Utilizarea legaturilor existente caz in care incercam sa folosim lanturile deja implementate. Atunci se evita definirea de legaturi explicite si se salveaza spatiu.
66
public class Handler
{
private Handler successor;
public void setSuccessor( Handler successor )
{ this.successor = successor;}
public Handler getSuccessor()
{return successor; }
public void handleRequest()
{successor.handleRequest(); }
}
67
public class ConcreteHandler2 extends Handler{
public void handleRequest()
{// executa o mica procesare asupra cererii si apoi trimite-o urmatorului din lant
getSuccessor().handleRequest();}
}
public class ConcreteHandler1 extends Handler{
public void handleRequest()
{// se presupune ca aici cererea trebuie tratata
if( expresia ce verifica daca cererea trb tratata aici == TRUE ){// trataeaza cerera. }
else getSuccessor().handleRequest();
}
} 68
public class Test{
public static void main( String arg[] ) {
try {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler1();
Handler handler3 = new ConcreteHandler1();
Handler handler4 = new ConcreteHandler1();
handler1.setSuccessor( handler2 );//incep crearea lant
handler2.setSuccessor( handler3 );
handler3.setSuccessor( handler4 );
handler1.handleRequest(); }
catch( Exception e ) {e.printStackTrace();}
}}69
Observator Aceasta abordare a aparut in urma unor constringeri
contrare.
Pe de o parte acest tip de interactiune este necesara si trebuie sa fie cit mai eficienta dar pe de alta o prima rezolvare ar conduce la o cuplare prea strinsa a claselor fapt ce nu este dorit deoarece scade dramatic posibilitatea de reutilizare a acestora.
Un exemplu tipic de aplicabilitate este in cazul interfetelor grafice ale unei aplicatii unde este necesara atat o separarea clara a acestora de datele de baza ale aplicatiei cit si o strinsa cooperare intre ele.
70
Aceasta tehnica se utilizeaza cind:
abstractizare are doua aspecte unul depinzind de celalat. Incapsularea acestor obiecte separate permite ca sa fie modificate si reutilizate independent
Modificarea.
anuntarea
71
72
73
Observer in Java
75
metoda Descriere
addObserver(Observer o) adauga un obiecte trimis ca argument catre listainterna de observatori.
deleteObserver (Observer o) Sterge din lista
deleteObservers() Sterge toti observatorii
notifyObservers (Object arg) daca obiectul curent a fost setat ca modificat(cu setChanged) apeleaza metoda update() a tuturor observatorilor din lista si le trimite nouaversiune a obiectului curent
notifyObservers() Similara cu anterioara dar fara argumente
countObservers() Numarul curent de observatori atasati unuiobiect observat
setChanged() Anunta ca starea obiect se schimbaSets the current object as changed.
hasChanged() True daca obiectul a fost setata ca schimbat
clearChanged() Reseteaza starea obiect curent la neschimbata(tot protected.)
Exemple: O componenta GUI “observa” o persoana
Java AWT 1.1 Event Model
event-driven programming
Example: event-driven programmingimport javax.swing.*; import java.awt.event.*; import java.awt.*;
import com.bruceeckel.swing.*;
public class Button2 extends JApplet {
JButton b1 = new JButton("Button 1"), b2 = new JButton("Button 2");
JTextField txt = new JTextField(10);
class BL implements ActionListener {
public void actionPerformed(ActionEvent e){
String name = ((JButton)e.getSource()).getText(); txt.setText(name);}
}
BL al = new BL();
public void init() {
b1.addActionListener(al); b2.addActionListener(al);
Container cp = getContentPane(); cp.setLayout(new FlowLayout());
cp.add(b1); cp.add(b2); cp.add(txt); }
public static void main(String[] args) {Console.run(new Button2(), 200, 75);}
}
Tratare
Eveniment
Surseeveniment
Evenimente
Inregistrarea gestionarevenimente la sursa lor
Modelul stare – State
81
public class Context{private State state;public void setState( State state )
{ this.state = state;}public State getState()
{ return state;}public void request(){state.handle();}
}public interface State{ void handle(); }
public class ConcreteStateB implements State{ public void handle()
{ }}
public class ConcreteStateA implements State{ public void handle()
{ }}public class Test{ public static void main( String arg[] )
{ try{State state = new ConcreteStateA();Context context = new Context();context.setState( state );context.request();}
catch( Exception e ){ e.printStackTrace();}
}}
82
Modelarea masinii TCP
83
Exista situatii in care avem foarte multe stari si mai mult acestea nu sunt asa de clar delimitate ca in cazul sa spunem al modelarii conexiunii tcp.
84
85
Intai clientul va crea un numar oarecare de instante ale clasei Stare
Apoi va crea instantele Tranzition si le va aduga la instantele State selectate.
In sfirsit va crea StateMachine prin transmiterea catreea a unei referinte catre instanta State initiala.
La apelul metodei Step din StateMachine ea va delega intern un apel catre instanta curenta a clasei Stare care va verifica daca o tranzitie care are simbolul dat (de exemplu obiectul parametru) a fost anterior definite.
Functie de aceasta metoda respective va decide daca va crea si intoarce o noua instanta de tip State care sa fie definite de Transition sau va genera o exceptie.
86
Modelul proxy Acesta asigura pentru un alt obiect un intermediar
sau inlocuior in scopul controlarii accesului la acesta.
Are principalul or de securitate deoarece permite realizarea unor filtrari functie de necesitati a fluxului de date.
87
88
Proxy pentru imagini swingimport java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class VirtualProxyTest extends JFrame {
private static String IMAGE_NAME = "mandrill.jpg";
private static int IMAGE_WIDTH = 256, IMAGE_HEIGHT = 256,
SPACING = 5, FRAME_X = 150, FRAME_Y = 200, FRAME_WIDTH = 530,
FRAME_HEIGHT = 286;
private Icon imageIcon = null, imageIconProxy = null;
static public void main(String args[]) {
VirtualProxyTest app = new VirtualProxyTest();
app.show();
}89
public VirtualProxyTest() {
super("Virtual Proxy Test");
// creaza iconita imaginii si proxy asociat ei.
imageIcon = new ImageIcon(IMAGE_NAME);
imageIconProxy = new ImageIconProxy(IMAGE_NAME, IMAGE_WIDTH, IMAGE_HEIGHT);
// seteaza dimensiunile frame si operatia implicita a acestuia
setBounds(FRAME_X, FRAME_Y, FRAME_WIDTH, FRAME_HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
super.paint(g);
Insets insets = getInsets();
imageIcon.paintIcon(this, g, insets.left, insets.top);
imageIconProxy.paintIcon(this, g,
insets.left + IMAGE_WIDTH + SPACING, // width
insets.top); // height
}
} 90
Interfata javax.swing.Icon care definesteelementele esentiale ale icoanelor Swing include trei metode paintIcon(), getIconWidth(), si getIconHeight.
Clasa ImageIcon care implementeazainterfata Icon mai adauga metode suplimentare.
Icoanele imagine poate mentine de asemenea o descriere si o referinta catreimagini
91
92
class ImageIconProxy implements javax.swing.Icon {
private Icon realIcon = null;
boolean isIconCreated = false;
private String imageName;
private int width, height;
public ImageIconProxy(String imageName, int width, int height){
this.imageName = imageName;
this.width = width;
this.height = height; }
public int getIconHeight() {
return isIconCreated ? height : realIcon.getIconHeight(); }
public int getIconWidth() {
return isIconCreated realIcon == null ? width : realIcon.getIconWidth();
}93
public void paintIcon(final Component c, Graphics g, int x, int y) {if(isIconCreated) {
realIcon.paintIcon(c, g, x, y); }else {g.drawRect(x, y, width-1, height-1);g.drawString("Loading image...", x+20,
y+20);// iconita este creata (deci imaginea se
incarca pe alt fir de executie. synchronized(this) {SwingUtilities.invokeLater(new
Runnable() {public void run() {try {
// intarzie procesul de incarcare a imaginii.
Thread.currentThread().sleep(2000);
//constructirul lui ImageIcon va crea//imaginea.
realIcon = new ImageIcon(imageName);
isIconCreated = true;}
catch(InterruptedException ex) {ex.printStackTrace();
}// reafiseaza componentele iconitei dupa//ce aceasta a fost creata.
c.repaint();}
});}
}}
}
94
ImageIconProxy mentine o referinta catre o icoana reala cu ajutorul variabilei membru realIcon.
La prima afisare a proxy icoana reala este creata intr-un thread separat pentru a permite dreptunghiului si textului sa fie afisat deoarece apelurile g.drawRect() si g.drawString() nu au efect pina la iesirea din metoda paintIcon().
Dupa ce icoana reala este creata si deci imaginea este incarcata componenta care afiseaza icoana este reafisata.
Mai jos este o diagrama de evenimente.
95
96
Referinte http://ooad.se.sjtu.edu.cn/ppt/Chap%206%20-
%20Design%20Patterns.ppt
http://www.vincehuston.org/dp/
http://www.dre.vanderbilt.edu/~schmidt/LiveLessons/#JavaSourceCode
http://java.dzone.com/articles/design-patterns-bridge
http://www.yaldex.com/java_tutorial/0939352869.htm
97
I applied design patterns and look what is happened?!
98