Necessità di aggiungere dinamicamente responsabilità a singoli oggetti e non all’intera classe



Scaricare 445 b.
13.11.2018
Dimensione del file445 b.





Necessità di aggiungere dinamicamente responsabilità a singoli oggetti e non all’intera classe.

  • Necessità di aggiungere dinamicamente responsabilità a singoli oggetti e non all’intera classe.



Esempio: durante l’uso di un’interfaccia grafica, dovrebbe essere possibile aggiungere (e togliere) ai componenti grafici proprietà quali bordi o barre di scorrimento. Per ottenere l’effetto desiderato si può procedere seguendo due vie:

  • Esempio: durante l’uso di un’interfaccia grafica, dovrebbe essere possibile aggiungere (e togliere) ai componenti grafici proprietà quali bordi o barre di scorrimento. Per ottenere l’effetto desiderato si può procedere seguendo due vie:



Usando l’ereditarietà. Ereditare una proprietà da una classe permette di utilizzare tale proprietà in ognuna delle sue sottoclassi.

  • Usando l’ereditarietà. Ereditare una proprietà da una classe permette di utilizzare tale proprietà in ognuna delle sue sottoclassi.



L’ereditarietà non è un approccio flessibile in quanto la proprietà viene aggiunta staticamente a tutte le sottoclassi; il client NON può controllare come e quando “decorare” un componente.

  • L’ereditarietà non è un approccio flessibile in quanto la proprietà viene aggiunta staticamente a tutte le sottoclassi; il client NON può controllare come e quando “decorare” un componente.



Racchiudendo il componente da decorare in un altro responsabile dell’aggiunta della proprietà.

  • Racchiudendo il componente da decorare in un altro responsabile dell’aggiunta della proprietà.

  • L’oggetto “contenitore” si chiama DECORATOR.

  • Approccio più flessibile.



Interfaccia TRASPARENTE e CONFORME a quella dell’oggetto da decorare per non rivelare la sua presenza ai client. Il Decorator delega le richieste al componente decorato, svolgendo anche azioni aggiuntive.

  • Interfaccia TRASPARENTE e CONFORME a quella dell’oggetto da decorare per non rivelare la sua presenza ai client. Il Decorator delega le richieste al componente decorato, svolgendo anche azioni aggiuntive.



Grazie alla trasparenza è possibile annidare i decoratori in maniera ricorsiva, con conseguente possibilità di aggiungere un numero illimitato di responsabilità ad un oggetto.

  • Grazie alla trasparenza è possibile annidare i decoratori in maniera ricorsiva, con conseguente possibilità di aggiungere un numero illimitato di responsabilità ad un oggetto.













Quando usare Decorator:

  • Quando usare Decorator:

  • Si vuole aggiungere responsabilità a singoli oggetti.

  • Si vuole togliere responsabilità agli oggetti

  • L’estensione attraverso la definizione di classi specifiche non è praticabile in quanto porterebbe ad un’esplosione del numero di sottoclassi.









Component: definisce l’interfaccia comune degli oggetti decorati e non

  • Component: definisce l’interfaccia comune degli oggetti decorati e non

  • ConcreteComponent: definisce l’oggetto da decorare

  • Decorator: mantiene un riferimento all’oggetto Component e definisce un’interfaccia conforme ad esso

  • ConcreteDecorator: aggiunge responsabilità





Conformità delle interfacce: l’interfaccia del decoratore deve essere conforme a quella dell’oggetto decorato; le classi ConcreteDecorator devono quindi ereditare da una superclasse comune.

  • Conformità delle interfacce: l’interfaccia del decoratore deve essere conforme a quella dell’oggetto decorato; le classi ConcreteDecorator devono quindi ereditare da una superclasse comune.

  • Omissione classe astratta Decorator: se esiste un solo tipo di decorazione o se stiamo lavorando su una gerarchia di classi preesistente è possibile omettere la classe astratta Decorator e semplificare il pattern; in questo caso le responsabilità di trasferimento delle richieste da Decorator a Component viene spostato nella classe ConcreteDecorator.



Classi Component leggere: per semplificare la conformità ConcreteComponent-Decorator si fanno discendere entrambe le classi da una classe comune Component. È importante mantenere il più possibile leggera questa classe, focalizzandosi sulla definizione dell’interfaccia e rinviando la memorizzazione dei dati alle sottoclassi; in questo modo si evita di appesantire i componenti Decorator con funzionalità non necessarie.

  • Classi Component leggere: per semplificare la conformità ConcreteComponent-Decorator si fanno discendere entrambe le classi da una classe comune Component. È importante mantenere il più possibile leggera questa classe, focalizzandosi sulla definizione dell’interfaccia e rinviando la memorizzazione dei dati alle sottoclassi; in questo modo si evita di appesantire i componenti Decorator con funzionalità non necessarie.

  • Cambiamento di “pelle” vs Cambiamento di “organi interni”: un decoratore può essere visto come un “rivestimento” che viene applicato su un oggetto in grado di modificarne il comportamento. Un ‘alternativa è fornita dal pattern Strategy: in questo caso il cambiamento avviene modificando gli “organi interni” (funzionalità interne dell’oggetto).



Nel Pattern Strategy il componente trasferisce parte del suo comportamento ad un oggetto Strategy separato.

  • Nel Pattern Strategy il componente trasferisce parte del suo comportamento ad un oggetto Strategy separato.





Definizione dell’interfaccia comune

  • Definizione dell’interfaccia comune



Creare il secondo livello di classi “Core”(TextView) e Decorator, entrambe in relazione IS-A con l’interfaccia VisualComponent. Decorator presenta una relazione HAS-A con VisualComponent.

  • Creare il secondo livello di classi “Core”(TextView) e Decorator, entrambe in relazione IS-A con l’interfaccia VisualComponent. Decorator presenta una relazione HAS-A con VisualComponent.





Creazione dei ConcreteDecorator (BorderDecorator, ScrollDecorator) sottoclassi di Decorator.

  • Creazione dei ConcreteDecorator (BorderDecorator, ScrollDecorator) sottoclassi di Decorator.





Il client può ora realizzare le composizioni desiderate.

  • Il client può ora realizzare le composizioni desiderate.





Gli stream sono astrazioni fondamentali per capire correttamente i processi di I/O; uno stream fornisce un’interfaccia in grado di convertire un oggetto in una sequenza di bit o caratteri, rendendo così possibile il salvataggio/caricamento degli oggetti in/da file. Una semplice implementazione di ciò potrebbe essere la seguente:

  • Gli stream sono astrazioni fondamentali per capire correttamente i processi di I/O; uno stream fornisce un’interfaccia in grado di convertire un oggetto in una sequenza di bit o caratteri, rendendo così possibile il salvataggio/caricamento degli oggetti in/da file. Una semplice implementazione di ciò potrebbe essere la seguente:



Ma supponiamo di voler poter gestire anche:

  • Ma supponiamo di voler poter gestire anche:

  • Compressione dello stream di dati con diversi algoritmi

  • Convertire lo stream dei dati utilizzando una codifica a 7-bit ASCII, in modo da poter inviare il flusso attraverso canali di comunicazione ASCII.

  • Il pattern Decorator fornisce una soluzione veloce:



La classe astratta Stream mantiene un Buffer interno e fornisce le operazioni di immissione dei dati nello stream ( PutInt(), PutString() ) e la funzione astratta per la gestione del buffer pieno HandleBufferFull().

  • La classe astratta Stream mantiene un Buffer interno e fornisce le operazioni di immissione dei dati nello stream ( PutInt(), PutString() ) e la funzione astratta per la gestione del buffer pieno HandleBufferFull().

  • La versione della funzione presente in FileStream sovrascrive la funzione astratta e trasferisce il buffer all’interno di un file.

  • La classe StreamDecorator mantiene riferimento ad un oggetto Stream e inoltra le richieste ad esso.

  • Le sottoclassi di StreamDecorator sovrascrivono il metodo HandleBufferFull e svolgono altre operazioni prima di chiamare HandleBufferFull della classe genitrice.



Creare un FileStream che comprime i suoi dati e converte i dati binari compressi in codifica 7-bit ASCII:

  • Creare un FileStream che comprime i suoi dati e converte i dati binari compressi in codifica 7-bit ASCII:



E. Gamma, R. Helm, R. Johnson, J. Vlissides. Design patterns - Elements of reusable object oriented software, Addison-Wesley, 1995

  • E. Gamma, R. Helm, R. Johnson, J. Vlissides. Design patterns - Elements of reusable object oriented software, Addison-Wesley, 1995

  • http://sourcemaking.com/design_patterns/decorator/java/3

  • Steven John Metsker, Design Patterns Java Workbook, Addison Wesley, 2002

  • Elaborato C. Tosoni A.A. 2007/2008





Condividi con i tuoi amici:


©astratto.info 2019
invia messaggio

    Pagina principale