Design pattern (traducibile in lingua italiana come "schema progettuale", "schema di progettazione", o "schema architetturale"), in informatica e specialmente nell'ambito dell'ingegneria del software, è un concetto che può essere definito "una soluzione progettuale generale ad un problema ricorrente". Si tratta di una descrizione o modello logico da applicare per la risoluzione di un problema che può presentarsi in diverse situazioni durante le fasi di progettazione e sviluppo del software, ancor prima della definizione dell'algoritmo risolutivo della parte computazionale. È un approccio spesso efficace nel contenere o ridurre il debito tecnico.
I design pattern orientati agli oggetti tipicamente mostrano relazioni ed interazioni tra classi o oggetti, senza specificare le classi applicative finali coinvolte, risiedendo quindi nel dominio dei moduli e delle interconnessioni. Ad un livello più alto sono invece i pattern architetturali che hanno un ambito ben più ampio, descrivendo un pattern complessivo adottato dall'intero sistema, la cui implementazione logica dà vita a un framework.
Storia
[modifica | modifica wikitesto]Il termine fu inizialmente introdotto in architettura in un celebre saggio di Christopher Alexander; in seguito, proprio l'opera di Alexander ispirò la nascita di un settore dell'ingegneria del software dedicato all'applicazione del concetto di design pattern alle architetture software, soprattutto orientato agli oggetti. Oggi, l'espressione design pattern viene usata principalmente con riferimento a questo particolare contesto.
Il tema dei pattern viene oggi considerato una delle linee principali di sviluppo dell'ingegneria del software object-oriented. Esso trova applicazioni in tutta una serie di contesti di grande interesse per l'industria del software, dallo sviluppo di software basato su componenti, ai sistemi aperti, ai framework e così via. La maggior parte dei linguaggi di programmazione moderni, e di tecnologie correlate, sono stati progettati (o modificati) tenendo conto anche dell'obiettivo di essere coerenti con questo approccio emergente allo sviluppo del software.
La nascita del "movimento" dei pattern in informatica si deve al celebre libro Design Patterns: Elementi per il riuso di software ad oggetti di Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides (1995). Grazie al successo di quest'opera, i suoi quattro autori divennero nomi talmente citati che la comunità scientifica iniziò, per brevità, a identificarli collettivamente con un nomignolo: la "banda dei quattro" (Gang of Four o GoF).
Struttura
[modifica | modifica wikitesto]Un design pattern è costituito da:
- il nome, costituito da una o due parole che siano il più possibile rappresentative del pattern stesso;
- il problema, ovvero la descrizione della situazione alla quale si può applicare il pattern. Può comprendere la descrizione di classi o di problemi di progettazione specifici, come anche una lista di condizioni perché sia necessario l'utilizzo del pattern;
- la soluzione, che descrive gli elementi costitutivi del progetto con le relazioni e relative implicazioni, senza però addentrarsi in una specifica implementazione. Il concetto è di presentare un problema astratto e la relativa configurazione di elementi adatta a risolverlo;
- le conseguenze, i risultati e i vincoli che derivano dall'applicazione del pattern. Sono fondamentali in quanto possono essere l'ago della bilancia nella scelta dei pattern: le conseguenze comprendono considerazioni di tempo e di spazio, possono descrivere implicazioni del pattern con alcuni linguaggi di programmazione e l'impatto con il resto del progetto.
L'uso di pattern nella descrizione di altri pattern dà origine ai cosiddetti linguaggi di pattern.
Classificazione
[modifica | modifica wikitesto]I design pattern possono essere classificati con diversi criteri, i più comuni dei quali sono quelli che evidenziano il tipo di problema che si cerca di risolvere. Il tipo di problema può essere legato ad uno specifico dominio progettuale (telecomunicazioni, reti, software) oppure, più comunemente, al problema progettuale in senso più ampio (nell'ingegneria del software, ad esempio, si può parlare di creazione, comportamento, navigazione di oggetti o strutture dati).
Nel loro libro la "banda dei quattro" identificò 23 tipi di design pattern, suddivisi in tre categorie: strutturali, creazionali e comportamentali.
Pattern creazionali
[modifica | modifica wikitesto]I pattern creazionali risolvono problematiche inerenti all'istanziazione degli oggetti
- L'abstract factory (letteralmente, "fabbrica astratta") fornisce un'interfaccia per creare famiglie di oggetti connessi o dipendenti tra loro, in modo che non ci sia necessità da parte degli utilizzatori di specificare i nomi delle classi concrete all'interno del proprio codice.
- Il builder ("costruttore") separa la costruzione di un oggetto complesso dalla sua rappresentazione, in modo che il processo di costruzione stesso possa creare diverse rappresentazioni.
- Il factory method ("metodo fabbrica") fornisce un'interfaccia per creare un oggetto, ma lascia che le sottoclassi decidano quale oggetto istanziare.
- La lazy initialization ("inizializzazione pigra") è la tattica di istanziare un oggetto solo nel momento in cui deve essere usato per la prima volta. È utilizzato spesso insieme al pattern factory method.
- Il prototype pattern ("prototipo") permette di creare nuovi oggetti clonando un oggetto iniziale, o prototipo.
- Il singleton ("singoletto") ha lo scopo di assicurare che di una classe possa essere creata una sola istanza in sistemi con un unico thread.
- Il double-checked locking ("Interblocco ricontrollato") ha lo scopo di assicurare che di una classe possa essere creata una sola istanza in sistemi multithread.
Pattern strutturali
[modifica | modifica wikitesto]I pattern strutturali risolvono problematiche inerenti alla struttura delle classi e degli oggetti.
- L'adapter ("adattatore") converte l'interfaccia di una classe in una interfaccia diversa.
- Bridge ("ponte") permette di separare l'astrazione di una classe dalla sua implementazione, per permettere loro di variare indipendentemente.
- Il composite ("composto"), utilizzato per dare la possibilità all'utilizzatore di manipolare gli oggetti in modo uniforme, organizza gli oggetti in una struttura ad albero.
- Il container ("contenitore") offre una soluzione alla rottura dell'incapsulamento per via dell'uso dell'ereditarietà.
- Il decorator ("decoratore") consente di aggiungere metodi a classi esistenti durante il run-time (cioè durante lo svolgimento del programma), permettendo una maggior flessibilità nell'aggiungere delle funzionalità agli oggetti.
- Extensibility ("estendibilità")
- Il façade ("facciata") permette, attraverso un'interfaccia più semplice, l'accesso a sottosistemi che espongono interfacce complesse e diverse tra loro.
- Flyweight ("peso piuma"), che permette di separare la parte variabile di una classe dalla parte che può essere riutilizzata.
- Proxy fornisce una rappresentazione di un oggetto di accesso difficile o che richiede un tempo importante per l'accesso o creazione. Il Proxy consente di posticipare l'accesso o creazione al momento in cui sia davvero richiesto.
- Pipes and filters ("condotti e filtri")
- Private class data ("dati di classe privati")
Pattern comportamentali
[modifica | modifica wikitesto]I pattern comportamentali forniscono soluzione alle più comuni tipologie di interazione tra gli oggetti.
- Chain of responsibility ("catena di responsabilità") diminuisce l'accoppiamento fra l'oggetto che effettua una richiesta e quello che la soddisfa, dando a più oggetti la possibilità di soddisfarla
- Il command ("comando") permette di isolare la porzione di codice che effettua un'azione dal codice che ne richiede l'esecuzione.
- Event listener ("ascoltatore di eventi")
- Hierarchical visitor ("visitatore di gerarchia")
- Interpreter ("interprete") dato un linguaggio, definisce una rappresentazione della sua grammatica insieme ad un interprete che utilizza questa rappresentazione per l'interpretazione delle espressioni in quel determinato linguaggio.
- L'iterator ("iteratore") risolve diversi problemi connessi all'accesso e alla navigazione attraverso gli elementi di una struttura dati, senza esporre i dettagli dell'implementazione e della struttura interna del contenitore.
- Il mediator ("mediatore") si interpone nelle comunicazioni tra oggetti, allo scopo di aggiornare lo stato del sistema quando uno qualunque di essi comunica un cambiamento del proprio stato.
- Il memento ("promemoria") è l'operazione di estrarre lo stato interno di un oggetto, senza violarne l'incapsulazione, e memorizzarlo per poterlo ripristinare in un momento successivo.
- L'observer ("osservatore") definisce una dipendenza uno a molti fra oggetti diversi, in maniera tale che se un oggetto cambia il suo stato, tutti gli oggetti dipendenti vengono notificati del cambiamento avvenuto e possono aggiornarsi.
- Single-serving visitor
- State ("stato") permette ad un oggetto di cambiare il suo comportamento al cambiare di un suo stato interno.
- Lo strategy ("strategia") è utile in quelle situazioni dove è necessario modificare dinamicamente gli algoritmi utilizzati da un'applicazione.
- Il template method ("metodo schema") permette di definire la struttura di un algoritmo lasciando alle sottoclassi il compito di implementarne alcuni passi come preferiscono.
- Il visitor ("visitatore") permette di separare un algoritmo dalla struttura di oggetti composti a cui è applicato, in modo da poter aggiungere nuovi comportamenti senza dover modificare la struttura stessa.
- Null object ("oggetto nullo") permette di sostituire un riferimento nullo con un oggetto che non fa nulla.
Altri tipi di pattern
[modifica | modifica wikitesto]Alcuni pattern definiti nella letteratura non operano a livello di design del sistema, non possono quindi essere definiti propriamente design pattern. Alcuni esempi sono:
Pattern architetturali
[modifica | modifica wikitesto]I pattern architetturali operano ad un livello diverso (e più ampio) rispetto ai design pattern, ed esprimono schemi di base per impostare l'organizzazione strutturale di un sistema software. In questi schemi si descrivono sottosistemi predefiniti insieme con i ruoli che essi assumono e le relazioni reciproche.
- Blackboard, architettura per applicazioni di intelligenza artificiale
- Broker
- Client-server, rappresenta un tipo di applicazione di rete nel quale un computer client istanzia l'interfaccia utente di un'applicazione connettendosi ad una server application o ad un sistema di database.
- Layers, architettura basata su layer
- Microkernel
- Model-view-Controller (abbreviato spesso in MVC), che consiste nel separare i componenti software che implementano il modello delle funzionalità di business (model), dai componenti che implementano la logica di presentazione (view) e da quelli di controllo che tali funzionalità utilizzano (controller).
- Model-view-viewmodel (spesso abbreviato in MVVM)
- Naked objects
- Pipes and filters
- Presentation Abstraction Control
- Reflection, fornisce un meccanismo per cambiare la struttura e il comportamento di sistemi software in modo dinamico. Supporta la modifica di aspetti fondamentali, quali tipo di strutture e meccanismi di chiamata di funzione.
- Repository, pattern architetturale legato ad aspetti di persistenza
- Front controller, pattern architetturale che prevede l'utilizzo di un singolo file per gestire tutte le richieste
- Data Access Object, per la gestione della persistenza: si tratta fondamentalmente di una classe con relativi metodi che rappresenta un'entità tabellare di un RDBMS.
- Data Transfer Object, per trasferire dati tra sottosistemi di un'applicazione software. I DTO sono spesso usati in congiunzione con gli oggetti di accesso ai dati (DAO) per recuperare i suddetti da una base di dati.
- Active record pattern, tipicamente utilizzato in librerie di persistenza e in Object-relational mapper.
Pattern di metodologia
[modifica | modifica wikitesto]- Responsibility, ossia "identificare chiaramente e dividere la responsabilità" assegnata a ciascun oggetto o componente del sistema, è il pattern metodologico basilare indicato nel libro Design Patterns.
- Make it run, make it right, make it fast, make it small
Pattern di concorrenza
[modifica | modifica wikitesto]Nel caso di processi che eseguono contemporaneamente delle attività su dati condivisi si parla di concorrenza. Alcuni design pattern sono stati sviluppati per mantenere sincronizzato lo stato dei dati in tali situazioni:
- Active Object
- Balking pattern
- Double checked locking pattern
- Guarded suspension
- Leaders/followers pattern
- Monitor Object, che consente soltanto un processo attivo al suo interno, al contempo non necessita di una codifica esplicita della mutua esclusione.
- Read-write lock pattern
- Scheduler pattern
- Thread pool pattern
- Thread-Specific Storage
- Token passing synchronization
- Reactor pattern
Bibliografia
[modifica | modifica wikitesto]- Gamma, E., Helm, R., Johnson, R. e Vlissides, J., Design Patterns: elementi per il riuso di software a oggetti, Addison Wesley, 1995, ISBN 88-7192-150-X
- Originale: Design Patterns: Elements of Reusable Object-Oriented Software, Addison Wesley, 1995, ISBN 0-201-63361-2
- Eckel, B., Thinking in Patterns with Java, MindView (draft)
Voci correlate
[modifica | modifica wikitesto]Altri progetti
[modifica | modifica wikitesto]- Wikimedia Commons contiene immagini o altri file sul design pattern
Collegamenti esterni
[modifica | modifica wikitesto]- design pattern, su sapere.it, De Agostini.
- (EN) Denis Howe, Design pattern, in Free On-line Dictionary of Computing. Disponibile con licenza GFDL
- Portland Pattern Repository, su c2.com.
- Hillside Patterns Library
- Filosofia dei pattern, su inf.unitn.it. URL consultato il 7 aprile 2005 (archiviato dall'url originale il 16 marzo 2005).
- Pagina dei pattern di Vince Huston, su vincehuston.org.
- GoF's Design Patterns in Java (in Italiano), su eii.pucv.cl. URL consultato il 6 giugno 2007 (archiviato dall'url originale il 27 marzo 2008).
Controllo di autorità | LCCN (EN) sh98003823 · GND (DE) 4546895-3 · BNE (ES) XX550686 (data) · J9U (EN, HE) 987007532683705171 |
---|