1
FACTORY METHOD
Scopo: CREAZIONALE
Raggio d’azione: BASATO SU CLASSI
Si puo chiamare anche “Virtual Constructor”
Definisce un’interfaccia per la creazione di un oggetto, lasciando alle
sottoclassi la decisione sulla classe concreta che sarà instanziata.
Consente di deferire la creazione di un oggetto alle sottoclassi.
I framework utilizzano classi astratte per definire e mantenere le relazioni tra
gli oggetti e spesso sono anche responsabili della creazione di questi oggetti.
Si consideri un framework per applicazioni in grado di presentare più
documenti agli utenti.
La classe Application è responsabile della gestione di oggetti conformi
all’interfaccia Document e della loro creazione. Application sa solo quando
dovrà creare un nuovo documento ma non di che tipo né come dovrà farlo. La
responsabilità è spostata all’esterno del framework: le sottoclassi di Application
devono fornire l’implementazione del metodo factory createDocument() in
modo da restituire un’istanza della classe appropriata.
-Struttura
Product (Document) : definisce l’interfaccia degli oggetti creati dal metodo
factory.
ConcreteProduct(MyDocument): implementa l’interfaccia Product.
Creator(Application): dichiara il metodo factory, nell’esempio protetto, che
restituisce un oggetto di tipo Product. Può invocare createProduct() per creare
un prodotto.
ConcreteCreator(MyApplication): sovrascrive createProduct in modo da
restituire una specifica istanza di ConcreteProduct. 2
-Conseguenze
Elimina la necessità di riferirsi a classi dipendenti dall’applicazione all’interno
del codice del framework.
Gli utilizzatori potrebbero essere costretti a definire sottoclassi di Creator per
creare un particolare oggetto ConcreteProduct.
Fornisce un punto di aggancio per le sottoclassi per la produzione di una
versione specializzata di un prodotto.
Connette gerarchie di classi parallele. Il metodo factory potrebbe essere
invocato da oggetti diversi dal Creator, vedi esempio.
-Gerarchie classi parallele
Figure è il tipo di base di figure geometriche manipolabili graficamente.
La logica di manipolazione può essere complicata e diversa da figura a figura.
Si può attribuire la responsabilità di implementare una logica di manipolazione
ad oggetti separati introducendo il tipo Manipulator.
Si ottiene una gerarchia parallela a quella delle Figure. Ogni classe che
implementa Figure ha il proprio metodo Figure, ha il proprio metodo factory per
creare l’apposito Manipulator.
Pattern correlati: Abstract Factory 3
BUILDER
Scopo: CREAZIONALE
Raggio d’azione: BASATO SU OGGETTI
Separare la costruzione di un oggetto complesso dalla sua rappresentazione, in
modo che lo stesso processo di costruzione possa essere utilizzato per creare
rappresentazioni diverse. Riutilizzare lo stesso tipo di creazione per diverse
rappresentazioni.
- Struttura
BuilderIF: specifica l’interfaccia astratta che crea le parti dell’oggetto Product
ConcreteBuilder: costruisce e assembla le parti del prodotto implementando
l’interfaccia Builder; definisce e tiene traccia della rappresentazione che crea.
Director: Costruisce l’oggettto utilizzando l’interfaccia Builder.
Product: rappresenta l’oggetto complesso e include le classi che definiscono le
parti che lo compongono, includendo le interfacce per assemblare le parti nel
risultato finale.
- Interazioni 4
Il client crea l’oggetto Director e lo configura tramite l’oggetto Builder
desiderato.
Il Director informa il Builder ogni volta che una parte di Product deve essere
costruita.
Il Builder riceve e gestisce le richieste dl Director e aggiunge le parti al Product.
Il client ottiene dal Builder il Product creato.
- Conseguenze
Consente di variare la rappresentazione interna di un prodotto
L’interfaccia del Builder consente di nascondere la rappresentazione, la
struttura interna dell’oggetto Product e il processo di costruzione. Per
modificare la rappresentazione del Product basta definire un nuovo tipo
di Builder.
Isola il codice per la costruzione e la rappresentazione
Migliora la modularizzazione incapsulando il modo di costruire e
rappresentare un oggetto complesso. Per i client non è necessario
conoscere le classi che definiscono la struttura interna del prodotto
perché esse non appaiono nell’interfaccia Builder.
Consente un migliore controllo del processo di produzione
A differenza di altri pattern creazionali che costruiscono il prodotto nella
sua interezza, in questo caso il prodotto viene costruito passo dopo passo
sotto il controllo del Director.
- Costruttori Telescopici
I metodi factory statici e i costruttori condividono una limitazione: non scalano
bene quando ci sono molti parametri. Di solito la soluzione più adottatta
consiste nel fornire più costruttori con le varie combinazioni di parametri
presenti. I costruttori telescopici funzionano ma il codice cliente risulta difficile
da scrivere e ancora più difficile da leggere. Per capire che parametro è,
bisogna calcolare la sua posizione.
- Soluzione JavaBeans
Si introduce un costruttore senza parametri per creare un oggetto. I parametri
richiesti si specificano invocando gli appositi metodi setter. Tuttavia siccome il
processo di costruzione è diviso in varie chiamate l’oggetto creato potrebbe
trovarsi in uno stato inconsistente. La classe non ha modo di verificare la
consistenza dei parametri. Preclude la possibilità di rendere gli oggetti della
classe immutabili.
La soluzione migliore consiste nel ricorrere all’uso del pattern Builder.
La classe Nutrition Facts definisce un builder come inner class statica. La classe
Builder riproduce nei suoi campi quelli della classe NutritionFacts.
La classe Builder introduce un metodo per ciascun parametro opzionale. Questi
metodi settano il parametro e restituiscono il builder stesso. Il metodo build
crea l’oggetto fornendo atomicamente tutti i parametri per mezzo del builder.
Si noti che la classe NutritionFacts è immutabile. Ecco come appare il codice
client:
NutritionFacts cocaCola = new 5
NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build()
;
Questo codice è molto più facile da leggere e da scrivere.
Il Builder può imporre degli invarianti sui parametri durante l’invocazione di
build(). Un singolo builder può essere utilizzato per creare più oggetti. Il builder
può riempire alcuni campi automaticamente come ad esempio il numero
seriale che si incrementa automaticamente ad ogni creazione.
BRIDGE
Scopo: STRUTTURALE
Raggio di azione : BASATO SU OGGETTI
Disaccoppia un’astrazione dalla sua implementazione in modo che le due
possano variare indipendentemente l’una dall’altra.
Altri nomi: Handle/Body
Quando un’astrazione può avere una tra più implementazioni possibili, in
genere si risolve il problema ricorrendo all’ereditarietà.
L’astrazione viene definita da un’interfaccia o da una classe astratta e le
sottoclassi concrete la implementano in modi differenti.
Tale approccio non è flessibile poiché l’ereditarietà lega un’implementazione ad
un’astrazione in modo permanente. Ciò rende difficile modificare, estendere e
riusare astrazioni ed implementazioni in modo indipendente.
- Applicabilità
Si vuole evitare un legame permanente tra un’astrazione e la sua
implementazione, come nel caso in cui l’implementazione deve poter essere
selezionata e/o modificata durante l’esecuzione.
Si vuole avere la possibilità di estendere sia le astrazioni che le
implementazioni per mezzo dell’ereditarietà. Tramite Bridge è possibile
combinare le astrazioni e le implementazioni in vario modo e di estendere le
une indipendentemente dalle altre.
I cambiamenti nell’implementazione di un’astrazione non devono avere
impatto sui client.
Si vuole condividere una stessa implementazione fra più oggetti nascondendo
questa condivisione ai client.
- Struttura 6
Abstraction: specifica l’interfaccia dell’astrazione. Mantiene un riferimento ad
un oggetto di tipo Implementor.
RefinedAbstraction: Estende l’interfaccia definita da Abstraction.
Implementor: definisce l’interfaccia per le classi che implementano
l’astrazione. Non deve corrispondere esattamente all’interfaccia di Abstraction:
Implementor fornisce le operazioni base, mentre Abstraction definisce
operazioni di più alto livello implementate sfruttando quelle di base.
ConcreteImplementor: definisce un’implementazione concreta
dell’interfaccia Implementor.
- Conseguenze
Disaccoppiamento tra interfaccia e implementazione
Un’implementazione non è più legata in modo permanente a
un’interfaccia. L’implementazione di un'astrazione può essere
configurata durante l’esecuzione. Il disaccoppiamento tra Abstraction ed
Implementor elimina la dipendenza dell’implementazione a tempo di
compilazione. Ciò aiuta ad ottenere una struttura stratificata del
sistema.
Maggiore estensibilità
Le gerarchie di classi Abstract e Implementor possono essere estese
indipendentemente.
Mascheramento dei dettagli dell’implementazione ai client
I client non devono preoccuparsi dei dettagli implementativi, quali per
esempio la condivisione di oggetti Implementor e il relativo meccanismo
di conteggio dei riferimenti.
Gestione delle risorse umane del progetto
Divisione di compiti: una parte si occupa dell’astrazione, l’altra della
parte concreta. La modularità di questo pattern permette quindi di
dividere il lavoro e quindi di lavorare in parallelo.
Pattern correlati: Abstract Factory può essere utilizzato per creare e
configurare un particolare Bridge.
- Adapter vs Bridge
Il pattern Adapter ha lo scopo di far cooperare tra di loro classi non correlate
dopo che sono state progettate. 7
Il pattern Bridge è utilizzato all’inizio di un progetto per consentire ad astrazioni
ed implementazioni di variare in modo indipendente. 8
FACADE
Scopo: STRUTTURALE
Raggio d’azione: BASATO SU OGGETTI
Fornire un’interfaccia unificata per un insieme di interfacce presenti in un
sottosistema.
Facade definisce un’interfaccia di livello più alto che rende il sistema più
semplice da utilizzare.
- Struttura
Facade (Message Creator): conosce le classi nel sottosistema che sono
responsabili di gestire una richiesta.
Classi del sottosistema (Message, MessageBody, Attachment):
implementano le funzionalità del sottosistema. Non hanno alcuna conoscenza
dell’esistenza del Facade: non hanno alcun riferimento ad esso.
- Conseguenze
Nasconde ai client i componenti del sottosistema, riducendo il numero
degli oggetti con cui i client interagiscono
Promuove un basso accoppiamento tra un sottosistema ed i suoi client. I
componenti del sottosistema sono molto accoppiati tra di loro (alta
coesione interna). La riduzione delle dipendenze è di fondamentale
importanza nei sistemi di grandi dimensioni.
In particolare, riduce le dipendenze di compilazione: se le classi del
sottosistema sono modificate non è necessario ricompilare il codice del
client.
Non impedisce alle applicazioni client di utilizzare le classi del
sottosistema qualora sia necessario
Pattern correlati: Abstract Factory , Mediator, Singleton 9
Abstract Factory
Scopo: CREAZIONALE
Raggio d’azione: BASATO SU OGGETTI
Altri nomi: Kit
Consente di creare famiglie di oggetti correlati, fornisce una interfaccia comune
sensza specificare classi concrete.
- Applicabilità
Un sistema deve essere indipendente dalla modalità di creazione,
composizione e rappresentazione dei suoi prodotti.
Un sistema deve poter essere configurato scegliendo tra più famiglie di
prodotti.
Esistono famiglie di oggetti correlati, progettati per essere usati insieme.
Si intende fornire una libreria di classi, rivelando le interfacce e nascondendo le
implementazioni.
AbstractFactory: dichiara un’interfaccia per le operazioni di creazione di
oggetti prodotto astratti.
ConcreteFactory: implementa le operazioni degli oggetti prodotto concreti.
Product: dichiara un’interfaccia per un tipo di prodotti.
ConcreteProduct: implementa l’interfaccia Product definendo un oggetto
prodotto creato dalla corrispondente factory concreta.
- Conseguenze
Isola le classi concrete. Poiché una classe factory incapsula il
processo di creazione dei prodotti concreti rende i clienti indipendenti
dalle classi utilizzate per la loro implementazione. I clienti conoscono
solo le interfacce dei prodotti.
Consente di cambiare in modo semplice la famiglia di prodotti
utilizzata. È possibile ottenere una configurazione di oggetti diversi
semplicemente cambiando il tipo di factory concreta utilizzata.
Promuove la coerenza nell’utilizzo dei prodotti.
L’aggiunta del supporto a nuove tipologie di prodotti è
difficile. L’aggiunta di un nuovo tipo di prodotto comporta una 10
modifica dell’interfaccia AbstractFactory e , di conseguenza, di tutte le
classi che la implementano.
- Implementazione
Factory come Singleton
Un’applicazione tipicamente richiede una singola istanza di factory
concreta per ciascuna famiglia di prodotti. Tale istanza è di solito
ottenuta per mezzo del pattern Singleton.
Creazione dei prodotti
Abstact Factory definisce un’interfaccia per la creazione di prodotti
mentre la responsabilità della creazione effettiva delle istanze
compete alle classi ConcreteProduct. Ciò può essere realizzato in vari
modi:
- introduzione di un metodo Factory per ogni prodotto.
- Ricorso al pattern Prototype: in questo caso la factory concreta
viene inizializzata con un’istanza prototipo di ciascun prodotto della
famiglia. La creazione dei prodotti avviene per clonazione dei
prototipi. 11
COMPOSITE
Scopo: STRUTTURALE
Raggio d’azione: BASATO SU OGGETTI
Comporre oggetti in strutture ad albero per rappresentare gerarchie parte-tutto
e consentire ai client di trattare oggetti singoli e composizioni in modo
uniforme
- Motivazione
Applicazioni quali editor grafici vettoriali o ambienti per la progettazione di
circuiti consentono agli utenti di costruire diagrammi complessi a partire da
semplici componenti.
Componenti semplici possono essere raggruppati per costruire componenti più
complessi che possono a loro volta essere utilizzati come parti di componenti
ancor più complessi.
Solitamente si introducono alcune classi per modellare gli oggetti semplici ed
altre per rappresentare gli oggetti ottenuti per composizione.
Il pattern Composite introduce un’interfaccia comune per gli oggetti semplici e
per quelli compositi in modo che il codice cliente li possa trattare
uniformemente.
Composite: dichiara l’interfaccia per gli oggetti componibili. Può essere una
classe astratta che fornisce un’implementazione di default per i metodi di
gestione dei componenti figli. Introduce (opzionale) un metodo per accedere al
componente genitore.
Leaf: rappresenta gli oggetti primitivi i quali non hanno figli.
Composite: definisce il comportamento dei componenti che hanno figli.
Memorizza i componenti figli e implementa i relativi metodi introdotti
dall’interfaccia Component.
- Conseguenze
Definisce gerarchie di classi costituite da oggetti primitivi ed oggetti
compositi. Gli oggetti primitivi possono essere composti per dare origine
ad oggetti più complessi. Il codice cliente tratta oggetti compositi e
primitivi in modo differente. 12
Il codice cliente non sa e non è interessato a saperlo se sta utilizzando un
oggetto primitivo o composito.
Rende semplice l’aggiunta di nuovi tipi di componenti senza influenzare il
codice cliente.
L’interfaccia Component potrebbe essere troppo generale. Può essere
necessario vincolare un particolare tipo di oggetto composito ad avere
solo determinati tipi di componenti. Il compilatore non può garantire tale
vincolo, per cui è necessario ricorrere a verifiche a tempo di esecuzione.
- Implementazione
Riferimenti al genitore
Fare in modo che ciascun componente conservi il riferimento al genitore
può semplificare le operazioni di gestione e di visita della struttura
composita. È importante fare in modo che tutti i figli di un oggetto
composito riferiscano a esso stesso come genitore. Il modo più semplice
per garantire ciò consiste nel modificare il riferimento al genitore
contestualmente alle operazioni di aggiunta e rimozione dei figli.
Massimizzazione dell’Interfaccia Component
Al fine di rendere uniforme l’interfaccia dei componenti, Component
potrebbe includere alcune operazioni che non hanno senso per i
componenti primitivi. Ciò è in contrasto con il principio secondo cui una
classe astratta dovrebbe includere solo le operazioni che hanno senso
per le sottoclassi.
Dichiarazione di metodi e gestione dei figli
Una scelta importante nell’implementazione del pattern riguarda il punto
in cui sono definite le operazioni di gestione dei figli. Nell’esempio esse
sono dichiarate da Component, un’alternativa sarebbe quella di
introdurle nella classe composite.
- la prima scelta garantisce l’uniformità di interfaccia ma, di contro, se
invocate su componenti primitivi tali operazioni falliscono o non hanno
effetto.
- nel secondo caso ci sono maggiori garanzie a tempo di compilazione ma
si perde in termini di trasparenza. 13
VISITOR
Scopo: COMPORTAMENTALE
Raggio d’azion
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
-
Schemi preparazione esame Matlab
-
Preparazione esame di Stato
-
Monografico Russo 2 - preparazione completa all'esame
-
Preparazione all'esame di GAL - Ingegneria Informatica