Design Patterns Luca Lista, Vincenzo Innocente L.Lista, V. Innocente Design Patterns E. Gamma et al., Design Patterns “Elementi di software OO riutilizzabile” • Piccoli insiemi di classi che collaborano implementando dei comportamenti tipici – Creational patterns – Structural patterns – Behavioral patterns Alcuni pattern classici stanno diventanto obsoleti grazie al supporto dei Template L.Lista, V. Innocente Factory Client Factory createProduct1 () : AbstractProduct createProduct2 () : AbstractProduct AbstractProduct I client possono richiedere la creazione di un prodotto senza dipendervi. La Factory dipende dai prodotti concreti, mentre i client dipendono solo AbstractProduct. ConcreteProduct1 L.Lista, V. Innocente ConcreteProduct2 Singleton _instance : Singleton instance () : Singleton specificService () Singleton if (_instance==0) _instance = new Singleton(); return _instance; user_code() { Singleton::instance()->specificService(...); } Il Singleton pattern piò essere usato ogni volta che una classe deve essere instanziata una sola volta, e viene usata da diversi oggetti. Per evitare istanziazione accidentale, il constructor deve essere privato. Più istanze, ma in numero ben determinato, possono esistere (multiton) Siccome vengono usate funzioni statiche, l’ereditarietà non può essere applicata. L.Lista, V. Innocente Singleton _ins tanceT : T ins tance () : T Singleton{V} V V( ) s pecificService( ) Template Singleton if (_ins tance==0) _ins tance = new T(); return _ins tance; class V : public Singleton<V> { public: specificService(...); private: V(); friend class Singleton<V>; }; user_code() { V::instance()->specificService(...); Un Template Singleton } può essere specializzato usando la classe stessa come argomento del template. Se V ha un constructor privato, Singleton<V> deve essere friend di V (non tutti i compilatori lo supportano…). L.Lista, V. Innocente Proxy Subject Client reques t( ) Proxy RealSubject _sub ject _s ubject : RealSubject reques t( ) 1 Una richiesta da un client a un server, può essere mediata dal Proxy, che può compiere anche altre operazioni (I/O, caching, etc.) L.Lista, V. Innocente reques t( ) ... _s ubject->reques t(); ... Composite Client Il client può trattare componenti e compositi usando la stessa interfaccia. La composizione può essere recursiva. Com ponent operation( ) 1..* _children Com pos ite operation( ) for c in all _children c->operation(); Leaf operation( ) Esempio: programmi di grafica vettoriale L.Lista, V. Innocente Composite Shape Client Nel nostro esempio di grafica con Shapes un gruppo può essere considerato un composito e le varie classi concrete sono le leaves. Shape draw( ) 1..* _children Gruppo draw( ) Cerchio, Rettangolo, ... draw( ) for c in all _children c->draw(); L.Lista, V. Innocente Collection e Iterator Collection _elements : Element Iterator friend append (Element) remove (Element) ... () rew ind () next () : Element* more () : bool 1 _elements 0..n Un iteratore permette più iterazioni indipendenti sulla stessa collezione. Questo sarebbe stato impossibile se l’iterazione fosse stato un servizio della collezione. Element Oggi, sia Collection che Iterator sono implementati come template classes (collezione “non intrusiva”). L.Lista, V. Innocente Strategy Il pattern Strategy permette di scegliere l’algoritmo da eseguire a run-time. { ... Strategy* s ; s ->doAlgorithm(); ... Nuovi algoritmi possono essere introdotti senza modificare i client. } Strategy Client doAlgorithm( ) ConcreteStrategyA doAlgorithm( ) ConcreteStrategyB doAlgorithm( ) L.Lista, V. Innocente ConcreteStrategyC doAlgorithm( ) Observer Subject Observer _ob servers update( ) _observers : Observer attach (Observer) notify () 0..* for all o in _ observables o->update(); ConcreteObserver ConcreteSubject _status : Status status( ) return _status; _sub ject Lo stato dell’Observer dipende dallo stato del Subject. Il Subject notifica a tutti gli Observer registrati che il suo stato è cambiato. L.Lista, V. Innocente _status : Status _subject . ConcreteSubject update( ) _status = _subject->status(); Template Method AbstractClass tem plateMethod( ) primitiveOperation1( ) primitiveOperation2( ) ... primitiveOperation1(); ... primitiveOperation2(); ... Un Template Method è un modo di garantire un comportamento comune. ConcreteClass primitiveOperation1( ) primitiveOperation2( ) Le operazioni elementari sono delegate alle sottoclassi. L.Lista, V. Innocente Visitor Client Vis itor vis it1 (ConcreteElem ent1) vis it2 (ConcreteElem ent2) Elem ent accept (Vis itor) ConcreteVisitor1 vis it1 (ConcreteElem ent1) vis it2 (ConcreteElem ent2) ConcreteElem ent1 ConcreteElem ent2 accept (Vis itor v) accept (Vis itor v) v->vis it1(this ) v->vis it2(this ) ConcreteVisitor2 vis it1 (ConcreteElem ent1) vis it2 (ConcreteElem ent2) Permette di aggiungere nuove operazioni a Element senza modificarne l’interfaccia. Per aggiungere nuovi ConcreteElement, bisogna modificare tutti i Visitors. L.Lista, V. Innocente