Articoli Manifesto Tools Links Canali Libri Contatti ?
Design / Design Patterns

Design Pattern, Framework e Metapattern

Abstract
In questo articolo, andando un po' contro corrente, vedremo cosa non sono i design pattern ed introdurremo la tematica dei framework e quella, correlata ed innovativa, dei metapattern.
Data di stesura: 31/12/2002
Data di pubblicazione: 31/01/2003
Ultima modifica: 04/04/2006
di Stefano Fago Discuti sul forum   Stampa

Design Pattern: un tool importante.

Uno dei tool concettuali largamente adottati negli ultimi anni dai professionisti del software è l'insieme dei design pattern: nomi come Abstract Factory, Command, Proxy e molti altri sono facilmente riscontrabili nella documentazione tecnico-realizzativa dei prodotti più recenti. In fase di sviluppo queste soluzione di design standard permettono di velocizzare la produzione di codice flessibile e quando impiegate con criterio permettono anche di aprire le porte alle evoluzione del prodotto. In rete è facile rilevare notizie a riguardo ed oramai le comunità interessate all'argomento sono molteplici.

Comprendiamo i Design Pattern.

Sfatiamo alcuni miti sui pattern sfruttando delle frasi tipo, comunemente riscontrate, espressione di una errata visione del ruolo di questi strumenti concettuali.

"Un pattern è una soluzione a un problema in un contesto": questa affermazione è parzialmente corretta ma omette un aspetto importante dei pattern ciò quello di essere riapplicabile per tutte le situazioni in cui il dato contesto si presenta, portando alla soluzione di una famiglia di problemi.

"I pattern sono regole, trucchi, strutture dati": l'affermazione è errata dato che un pattern è in primis uno strumento concettuale del tutto svincolato dall'aspetto implementativo; anche per questo non può essere applicato meccanicamente come una regola ma necessita di training e ragionamento.

"Visto uno, visti tutti" : l'affermazione risulta errata in quanto non solo è possibile distinguere i pattern per il loro scopo, ma esiste un ampio range di stili, dettagli, maturità, qualità.

"I pattern necessitano di appositi tool e supporto metodologico per essere effettivamente utilizzabili": in quanto strumento concettuale un pattern non è legato ad uno specifico tool o supporto metodologico. È da evidenziarsi però il fatto che la metodologia object oriented si presenta come terreno fertile per la crescita dei pattern e l'automazione del loro processo descrittivo.

"I pattern garantiscono software con alti livelli di riusabilità e produttività"
"I pattern permettono la generazione di un'intera architettura".
I pattern non danno garanzie di alcun tipo sono però uno strumento concettuale che se opportunamente usato favorisce, in ultima analisi, la flessibilità e riusabilità di un progetto. Negli ultimi anni anche i CASE Tool supportano i pattern e sembrerebbero affermare i design pattern come strumento per costruire software o per realizzazioni prototipali, portando in secondo piano la loro natura concettuale. È necessario, allora, evidenziare che questo risultato è conseguenza dell'adozione dei pattern e della standardizzazione di alcuni scenari che permette di sfruttare date combinazioni di pattern come struttura embrionale per differenti progetti specie di e-commerce!

"I pattern sono per implementazione e design orientato agli oggetti": Questa affermazione viene facilmente smentita considerando il fatto che i DESIGN PATTERN sono solo una parte di una famiglia di tool concettuali che riguarda anche altri aspetti dell'ingegneria del software. Il fatto che le comunità legate al design object oriented siano state particolarmente ricettive sull'argomento, non deve elidere il carattere di generalità dei pattern.

"Non c'è alcuna evidenza che i pattern aiutino qualcuno" : È estremamente semplice trovare documentazione ed esperienze concrete che dimostrino l'apporto positivo determinatosi dalla diffusione dei pattern in generale.

In conclusione i pattern sono:

  • soluzioni riusabili per problemi ricorrenti
  • strumenti concettuali che catturano la soluzione di una famiglia di problemi
  • strumenti concettuali utili anche ad esprimere architetture vincenti.

ma devono possedere un nome per essere facilmente riferiti ed ne devono essere puntualmente descritti i possibili trade-off (limiti, conseguenze, vantaggi, variazioni, suggerimenti implemetativi).

Framework: cosa sono?

Uno dei concetti a cui l'Object Orientation tende è sicuramente quella di riuso: riuso del codice grazie all'ereditarietà, riuso dei design grazie ai pattern!
"Un framework è un design riusabile di tutto o parte di un sistema, rappresentato da un insieme di classi astratte e dal modo in cui le loro istanze interagiscono". "Un framework è lo scheletro di un'applicazione che può essere customizzato da uno sviluppatore". Le due definizioni esposte possono sembrare in contraddizione ma in realtà presentano due aspetti dello stesso concetto: la prima descrive la struttura di un framework, mentre la seconda ne evidenzia lo scopo. Un framework rende possibile ottenere sia riuso del codice che di design. Comprendere il concetto in esame vuol dire comprendere gli elementi alla sua base, riassumibili in: uso di classi astratte, adozione di un modello collaborativo, inversione del flusso di controllo.

Una classe astratta è una classe che possiede almeno un metodo non implementato, definito astratto. Se normalmente una classe è considerata lo "stampo" per la creazione di oggetti, una classe astratta è il " template" per le sottoclassi da cui deriveranno le specifiche applicazioni.
Le classi astratte sono il progetto delle componenti di un framework!

Un framework è rappresentato da un'insieme di classi astratte e da come queste interagiscono. Quest'ultimo aspetto implica la definizione del framework come MODELLO COLLABORATIVO riferito alle componenti del framework stesso.
Un framework si pone come pattern dell'interazione tra le sue componenti ed in ciò si esprime la sua capacità di riuso del design!

Lo sviluppatore non scrive codice per coordinare le componenti. Lo sviluppatore deve determinare le componenti che aderendo alla logica collaborativa del framework verranno coordinate da quest'ultimo. I framework assumono il controllo della applicazione e non il contrario!

Frameworks e Metapatterns

Il rapporto con i DESIGN PATTERN della G.o.F. è particolare ed è stretto. Il perché sta nel fatto che i pattern in questione nascono essenzialmente da un'opera di disamina di framework vincenti onde isolare entità object oriented riusabili.
I Design Pattern possono essere visti come gli elementi micro-architetturali dei frameworks!
Costruire un framework in modo opportuno non deve però essere visto come una semplice operazione di aggregazione di elementi di design; è un'azione non banale i cui obiettivi sono il riuso e la flessibilità, elementi che spesso sono contrastanti, specie se ad essi si affiancano considerazioni sulle performance.
Un lavoro particolarmente importante a questo proposito è quello condotto da Wolfgang Pree relativo ai metapattern. L'obiettivo dell'opera di Pree è quello di fornire un tool semplice ma potente per accelerare lo sviluppo di framework. Questo è possibile usando i concetti chiave sottesi ai framework ed innalzando il livello di astrazione considerato: gli elementi di design determinati si offrono come fondamentali building block nella creazione di nuovi framework.
Termini di riferimento del lavoro di Pree sono:

  • Frozen Spot: elemento di invariabilità in un framework;
  • Hot Spot: Elemento di variazione che determina la flessibilità di un framework;
  • Template Method: metodo di una classe astratta che coordina generalmente più hook method;
  • Hook Method: metodo astratto che determina il comportamento specifico nelle sottoclassi di un framework

Il punto di partenza considerato è l'osservazione che nelle diverse componenti di un framework sono evidenziabili dei punti di variazione (classi e/o metodi) che permettono l'adattamento, anche a run-time, del framework in relazione ad una specifica applicazione. Tali elementi sono gli HOT SPOT.
Hot Spot e Frozen Spot si traducono nel meta-livello proposto da Pree in HOOK e TEMPLATE, i principali metapattern che consideriamo. La diversa collocazione di tali elementi e la loro diversa composizione determinano ulteriori elementi necessari a completare il quadro d'interesse:

Unification : template e hook sono nella stessa classe del framework.

[Figura 1]

Figura 1

Separation: hook e template sono in classi separate indicate rispettivamente come hook class e template class. Da questo metapattern derivano quelli indicati come connection e recursive connection.

[Figura 2]

Figura 2

Connection: con relazioni 1:1 e 1:n
[Figura 3]

Figura 3

Recursive Connection: questa volta risulta che la template class e sottoclasse della hook class con relazioni 1:1 e 1:n

[Figura 4]

Figura 4

È possibile ricondursi ai GoF pattern nel nuovo metalivello, attribuendo in modo opportuno il ruolo di Hook o Template Class agli elementi in gioco:

  • i G.o.F. pattern riconducibili al separation metapattern sono :Abstract Factory, Builder, Command, Interpreter, Observer, Prototype, State, Strategy.
  • i G.o.F. pattern riconducibili al recursive combination pattern: Composite(1:n), Decorator(1:1), Chain Of Responsibility (1:1 con unification).

Un piccolo esempio: mini-framework di contabilità!

Vediamo un piccolo esempio nell'utilizzo dei metapattern.
Supponiamo di voler sviluppare un framework relativo alla contabilità. Tra gli elementi da considerare sicuramente servirà sviluppare la logica associativa tra operazioni e movimenti contabili. In questo tipo di realtà sono possibili moltissime operazioni e combinazioni ad esse legate: questa considerazione rende evidente l'impossibilità di ragionare in termini procedurali ed adottare una sensibile porzione di codice sviluppata attorno ad un "groviglio" di if-then o switch!
Quello che ci serve è un metodo unico ma che si comporti in modo differente in base all'operazione contabile da esaminare. La reazione scatenata potrebbe essere un aggregato di elementi e far parte di una famiglia di azioni simili che vorremmo catalogare in una gerarchia da sviluppare per ereditarietà.

Analizzando le prime considerazioni quello che ci serve è nel separation metapattern dato che necessitiamo di un metodo (template) che invocato porti un risultato in base al comportamento di una o più specifiche azioni (hook callback). Possiamo allora pensare ad una classe Contabilizzatore (template class) che possiede un metodo registrazioneContabile (template method) a cui fornire una data operazione presentata come apposita classe OperazioneContabile (hook class). Quest'ultima astrazione potrebbe essere la base-class per una gerarchia di elementi che per ereditarietà specializzano il comportamento di una data operazione: questo grazie all'overriding del metodo movimentazioneContabile (hook method) dichiarato nella root-class.
Vediamo un po' di codice.

public class Contabilizzatore
{
  ...

  public boolean registrazioneContabile(OperazioneContabile operazione)
  {
    ...
    operazione.movimentazioneContabile();
    ...
  }

  ...
}

public abstract class OperazioneContabile
{
  ...

  public abstract void movimentazioneContabile();

  ...
}

public class OperazioneSuImmobile extends OperazioneContabile
{
  ...

  public void movimentazioneContabile()
  {
    ...
  }

  ...
}

Arrivati a questo punto vorremmo trattare anche aggregati di operazioni e quindi fornire il nostro contabilizzatore di un metodo che tratti anche insiemi. Vogliamo, altresì, mantenere il rapporto di ereditarietà che è emerso come importante nel nostro prodotto. Quello che vogliamo in conclusione è che l'aggregato e gli elementi componenti siano dello stesso tipo e che il contabilizzatore sia in grado di trattare questa situazione senza doversi preoccupare di sapere se abbiamo una singola o un insieme di operazioni. Quello che ci serve è nel metapattern recursive connection dove la hook class è OperazioneContabile e la template class sarà l'astrazione OperazioneComposta che con il metodo gestisciOperazioniAggregate può scatenare e raggruppare l'attività delle proprie componenti.
Vediamo il codice.

public class OperazioneComposta extends OperazioneContabile
{
  ...

  private OperazioneContabile[] operazioni = ...
  private int index;

  public void addOperazione(OperazioneContabile operazione)
  {
    operazioni[index++] = operazione;
    ...
  }

  public void movimentazioneContabile()
  {
    ...
    gestisciOperazioniAggregate();
    ...
  }
  
  protected void gestisciOperazioniAggregate()
  {
    for (int idx = 0; idx<operazioni.lenght; idx++)
      operazioni[idx].movimentazioneContabile();
  }

  ...
}

Proviamo a rivedere quanto ottenuto in versione UML, secondo il diagramma seguente:

[Figura 5]

Figura 5

I lettori più attenti avranno individuato subito l'applicazione di due G.o.F. design pattern: Strategy e Composite. Il primo è legato all'astrazione OperazioneContabile ad al metodo movimentazioneContabile, mentre il secondo riguarda le astrazioni OperazioneContabile e OperazioneComposta. L'aspetto interessante dei metapattern è anche questo: abbiamo utilizzato una logica svincolata dai design pattern, usando una modalità discorsiva. Il risultato finale ha, però, una connessione ai principi e pattern di design comunemente accettati ed utilizzati.
A questo punto precisiamo che la vera applicazione dei metapattern si concretizza in un lavoro più ampio indicato come UML-F: questo è una particolare estensione di UML sviluppata per supportare la creazione di framework grazie all'ausilio dei metapattern. In UML-F sono presenti nuovi stereotipi e tag che permettono di evidenziare ruoli tra astrazioni come nel caso in cui è necessario indicare quale concetto è un elemento template o hook, così come altri particolari riguardo la dinamicità o meno di metodi e classi!

Informazioni sull'autore

Stefano Fago, classe 1973. Diplomato in ragioneria, ha conseguito il Diploma di Laurea in Informatica con un progetto legato alle interfacce grafiche soft-realtime in Java. Dopo esperienze in Alcatel ed Elea, ha svolto attività di consulenza come Software Developer e Trainer alla ObjectWay S.p.A. sede di Milano. Attualmente Software Designer presso la sezione Innovazione e Attività Progettuali di BPU Banca. Appassionato del linguaggio Java e di tutte le tecnolgie Object Oriented. Polistrumentista dilettante.

È possibile consultare l'elenco degli articoli scritti da Stefano Fago.

Altri articoli sul tema Design / Design Patterns.

Risorse

  1. Framework Development and Reuse Support (Paper) Wolfgang Pree
  2. UML-F: A Modelling Language for Object Oriented Frameworks(Paper) W. Pree, M. Fontoura, B. Rumpe
Discuti sul forum   Stampa

Cosa ne pensi di questo articolo?

Discussioni

Questo articolo o l'argomento ti ha interessato? Parliamone.