MokaByte Numero 28  -  marzo  1999
Pattern composite
La teoria
di 
Lorenzo Bettini


Le gerarchie di classi riflettono spesso anche la disposizione e la dipendenza fisica di vari oggetti accomunati da una qualche proprietà e struttura; vediamo questo pattern, Composite, che rispecchia proprio questa situazione e la risolve in modo pratico ed elegante.

 
Introduzione al problema

A volte il concetto di gerarchia di classi sembra qualcosa di puramente teorico, nonostante sempre utile dal punto di vista pratico, relazionando oggetti che apparentemente non sono relazionati.
Inoltre spesso, molti di questi oggetti contengono al loro interno oggetti della stessa gerarchia (hanno una sorta di struttura ricorsiva dal punto di vista del tipo di oggetti, anche se a run time si tratta di oggetti di classi derivate).
Ovviamente tali oggetti devono essere gestiti in modo diverso, ma questo non è un problema grazie al meccanismo del polimorfismo, tipico della programmazione ad oggetti e quindi di Java.
Si hanno quindi in questi casi dei container di altri oggetti che a loro volta possono essere container, e così via ricorsivamente. Il punto fondamentale di queste situazioni è NON trattare differentemente container ed oggetti contenuti, proprio a causa del nesting implicito che si viene a formarsi, o può venirsi a formare grazie al riuso (che nella programmazione ad oggetti è un key concept, nonché, spesso, una giustificazione dell'utilizzo di un tale paradigma). La distinzione fra questi tipi di oggetti appesantirebbe il codice inutilmente e sarebbe innaturale, in quanto intuitivamente dovrebbero essere trattati allo stesso modo (o almeno questo appare agli occhi dell'utente).
Un esempio classico di questa situazione può essere ritrovato in un editor grafico in cui si hanno oggetti semplici come linee e punti, ed altri oggetti geometrici come rettangoli, cerchi, che possono contenere al loro interno (raggruppare) altri oggetti semplici, o a loro volta altri oggetti più complessi; questi ultimi possono essere considerati quindi oggetti composti.
Un altro esempio si può trovare in molti framework per la programmazione a finestre, in cui si ha il concetto astratto di oggetto grafico (o finestra o vista), che al suo interno può contenere altri oggetti grafici (caselle di testo, label, bottoni), ma anche oggetti composti (cornici di raggruppamento); il nesting, anche se spesso si ferma la primo livello, concettualmente (e giustamente) deve essere illimitato.
L'esempio classico di [GOF95] è quello della struttura di un documento di un word processor: il documento può essere suddiviso in colonne, suddivise in righe, suddivisi in caratteri, ma si possono anche avere delle cornici, che a loro volta possono contenere colonne, e così via; inoltre un word processor che si rispetti deve permettere di includere oggetti grafici, e quindi il quadro si complica ulteriormente richiedendo una soluzione apposita, ben studiata, ed ovviamente riutilizzabile e facilmente estendibile.
 

Il pattern Composite

La chiave della soluzione, per quanto appena detto, sta proprio nel non considerare differenti oggetti contenitori ed oggetti contenuti: cioè creare una classe astratta che rappresenti entrambi questi tipi di oggetto. Inoltre l'oggetto composto dovrà fornire metodi che siano applicabili (ricorsivamente e trasparentemente) a tutti gli oggetti contenuti; le operazioni saranno quindi propagate a tutti gli oggetti contenuti in un contenitore.
Vediamo in modo più formale i partecipanti a questo pattern:

  • Componente: definisce proprio la classe astratta appena citata ed la chiave della soluzione che stiamo cercando.
  • foglia: rappresenta un oggetto semplice (eventualmente contenuto in un oggetto composto) e che non contiene a sua volta nessun altro oggetto.
  • composite: è un componente che al proprio interno contiene altri componenti (che quindi potranno essere o foglie o ricorsivamente oggetti composti).
Ovviamente il tutto è trasparente al client di questi oggetti che manipolerà ed utilizzerà tali oggetti come componenti e non, salvo situazioni particolare, come, distintamente, foglie e oggetti composti. La struttura è rappresentata come sempre in UML nella seguente figura:

si può assimilare questa situazione ad una struttura ad albero in cui le foglie rappresentano appunto il loro omonimo in tale struttura (non sono state chiamate così per caso), ed i composite rappresentano nodi con figli (che apparterranno, ricorsivamente alla classe componente).
 

Conclusioni

Il pattern composite è senz'altro fra i più utilizzati quando si scrivono dei framework o comunque si ha a che fare con strutture ricorsive più complesse di liste o anche alberi.
Ovviamente tale pattern si può ritrovare più o meno mascherato insieme ad altri pattern, ma questa si sa è una caratteristica di queste metodologie di design e sviluppo.
Notare inoltre, che nonostante si tratti di una soluzione molto potente ed già utilizzata in passato, la struttura è relativamente semplice, ma questo, come sempre, non deve spingere ad utilizzare il pattern senza prima avere chiare le varie caratteristiche che accomunano tutti gli elementi dei vari componenti; anzi dovrebbe spingere a fare uno studio attento di quelle caratteristiche che da sole rappresentano tutti i componenti, spostando eventuali altri, meno caratteristici, sono nelle parti basse della gerarchi, senza che questo ne limiti l'utilizzo trasparente.
Vi lascio adesso ad Andrea Trentini, che vi mostrerà qualche esempio concreto di implementazione di quanto visto finora.

Lorenzo
Bibliografia
    [GOF95] E.Gamma, R.Helm, R.Johnson, J.Vlissides, Design Patterns, Elements of Reusable Object-Oriented Software, 1995, Addison-Wesley.

 

MokaByte Web  1999 - www.mokabyte.it

MokaByte ricerca nuovi collaboratori. 
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it