Il pattern Decorator

Aggiungere comportamenti e caratteristiche con Decorator

Il pattern Decorator si occupa dell’aggiunta di funzionalità, comportamenti e caratteristiche, in modo dinamico ad una classe. L’aggiunta avviene in maniera alternativa all’ereditarietà e non attraverso interfacce, ma privilegiando la composizione. Un esempio d’uso del pattern Decorator è l’aggiunta dei bordi o delle barre di scorrimento alla finestra di un programma.
Questo pattern è di tipo strutturale e nonostante il nome possa trarre in inganno, può essere applicato sia a componenti grafici che a componenti non grafici dato che “aggiunge semplicemente funzionalità”.

Nel codice seguente aggiungiamo ad un’aria di testo delle barre di scorrimento:

  // Area di testo con 5 righe e 10 colonne
  Component area = new JTextArea(5, 10);

  // Aggiunta delle barre di scorrimento
  Component scrollArea = new JScrollPane(area);

Come si può vedere, bisogna creare un nuovo oggetto di tipo effettivo JScrollPane, a partire dall’oggetto JTextArea esistente. L’oggetto così creato è a sua volta sottotipo di Component.

  1. Contesto:

      Si vuole decorare aggiungendo funzionalità ad una classe componente;
    • Un componente decorato può essere utilizzato nello stesso modo di uno componente normale;
    • La classe componente non vuole assumersi la responsabilità della decorazione;
    • L’insieme delle decorazioni possibili non è limitato.
  2. Soluzione:
    • Definire un’interfaccia (Component) che rappresenti un’astrazione di un componente;
    • Le classi concrete che definiscono componenti implementano l’interfaccia Component;
    • Definire una classe (Decorator) che rappresenta la decorazione;
    • Un oggetto decoratore contiene e gestisce l’oggetto che decora;
    • Un oggetto decoratore implementa l’interfaccia Component;
    • Nel realizzare un metodo di Component, un oggetto decoratore applica il metodo corrispondente all’oggetto decorato e ne combina il risultato con l’effetto della decorazione.

Il pattern Decorator

L’interfaccia Component rappresenta un componente generico. Sia i veri componenti base (ConcreteComponent) che le loro decorazioni (Decorator) implementano l’interfaccia, in modo che il client li possa usare nello stesso modo.
La relazione di aggregazione indica che un oggetto decoratore contiene un riferimento al componente che sta decorando, presumibilmente, tale riferimento viene inizializzato tramite un costruttore o metodo di Decorator. In questo modo si evita la possibilità di avere decoratori senza Component.

Il pattern Decorator applicato alla classe JScrollPane di Java

Il pattern Decorator

In Java il pattern Decorator è stato applicato alla libreria Swing/AWT. Sia il campo di testo (JTextArea) che le barre di scorrimento (JScrollPane) estendono la classe Component.
Il costruttore di JScrollPane prende come argomento il componente a cui applicare la decorazione. Quando un client chiama paint (il metodo che chiede ad un componente di disegnare il suo contenuto) di un oggetto JScrollPane, quest’ultimo chiama il metodo omonimo dell’oggetto decorato e poi aggiunge il disegno delle barre di scorrimento.

Ci sono molte similitudini tra il pattern Composite e il pattern Decorator, hanno descrizioni e diagrammi molto simili. Entrambi i pattern prevedono una distinzione tra oggetti di base (chiamati primitivi in un caso e componenti nell’altro) e oggetti compositi. Entrambi prevedono che gli oggetti delle due categorie implementino un’interfaccia comune. Tuttavia, i contesti di applicazione sono molto diversi:

  • Composite, si applica quando bisogna aggregare più oggetti base in un unico oggetto, che può a sua volta essere aggregato con altri; si ottengono così gerarchie di oggetti disposti in un albero;
  • Decorator, si applica quando bisogna aggiungere funzionalità, illimitate a priori, ad una o più classi.

Un altro esempio del pattern Decorator è quello relativo alle classi I/O di Java. Le classi fondamentali per l’I/O sono: InputStream, OutputStream, Reader e Writer. E’ possibile aggiungere altre funzionalità attraverso delle classi “filter” che sono applicazioni del pattern decorator. In particolare:

  • DataStream, funzioni su tipi primitivi;
  • BufferedStream, consente l’utilizzo di un buffer;
  • PushBackStream, permette le operazioni “UNDO“.
  public class JavaIO {
    public static void main(String[] args) {
      // Open an InputStream.
      FileInputStream in = new FileInputStream("test.dat");
      // Create a buffered InputStream.
      BufferedInputStream bin = new BufferedInputStream(in);
      // Create a buffered, data InputStream.
      DataInputStream dbin = new DataInputStream(bin);
      // Create an unbuffered, data InputStream.
      DataInputStream din = new DataInputStream(in);
      // Create a buffered, pushback, data InputStream.
      PushbackInputStream pbdbin = new PushbackInputStream(dbin);
    }
  }

Per la lista completa di tutti i design pattern fate riferimento a questa pagina.

Pubblicato in Design Pattern, Guide, Java, Programmazione Taggato con: , , , , ,

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

*