Allegare responsabilità aggiuntive a un oggetto dinamicamente, offrendo un'alternativa flessibile all'uso delle sottoclassi per estendere la funzionalità.
Per aggiungere responsabilità a oggetti specifici, non a un'intera classe.
Per evitare approcci rigidi come l'ereditarietà, che impone scelte statiche e non permette dinamismo.
Per consentire ai client di controllare dinamicamente come e quando decorare i componenti.
Per supportare funzionalità annidabili e ricorsive, come bordi o scorrimento per componenti UI.
Quando vuoi aggiungere responsabilità dinamicamente a oggetti individuali senza influenzare altri oggetti.
Quando le responsabilità devono essere rimovibili.
Quando l'ereditarietà risulta impraticabile, ad esempio con un gran numero di estensioni indipendenti o classi non accessibili per sottoclassificazione.
Component (VisualComponent):
Definisce l'interfaccia per gli oggetti decorabili.
ConcreteComponent (TextView):
Oggetto di base a cui possono essere aggiunte responsabilità.
Decorator:
Mantiene un riferimento al Component e si conforma alla sua interfaccia.
ConcreteDecorator (BorderDecorator, ecc.):
Aggiunge responsabilità specifiche al Component.
Il Decorator inoltra le richieste al componente decorato e può aggiungere comportamenti aggiuntivi prima o dopo l'inoltro.
I Decorator possono essere annidati, permettendo di combinare responsabilità in modo flessibile e ricorsivo.
Vantaggi:
Maggiore flessibilità rispetto all'ereditarietà statica.
Possibilità di aggiungere e rimuovere responsabilità a runtime.
Approccio "pay-as-you-go" per aggiungere funzionalità incrementali.
Evita classi sovraccariche di funzionalità in cima alla gerarchia.
Svantaggi:
Un decoratore e il componente decorato non sono identici, causando problemi con l'identità degli oggetti.
Introduce molti piccoli oggetti che possono rendere difficile imparare, personalizzare e fare il debug del sistema.
Conformità dell'interfaccia: I Decorator devono conformarsi all'interfaccia del Component.
Omettere la classe astratta Decorator: Utile se si aggiunge solo una responsabilità o si lavora con una gerarchia esistente.
Mantenere leggere le classi Component:
L'interfaccia deve essere focalizzata e leggera.
I dati e le implementazioni concrete vanno delegati ai Decorator o alle sottoclassi concrete.
Uso incrementale dei Decorator: Consentire un annidamento ricorsivo dei Decorator per aggiungere funzionalità multiple senza introdurre rigidità.
Nei framework come lo zoo degli stream di Java, dove i Decorator aggiungono funzionalità come buffer, compressione o crittografia agli stream.
Adapter: Per adattare interfacce incompatibili.
Composite: Per gestire strutture gerarchiche di oggetti decorabili.
Strategy: Per separare algoritmi in modo intercambiabile.