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.
vuoi
o PayPal
tutte le volte che vuoi
GRASP
UML descrive una responsabilità come “un contratto o un obbligo di un
classificatore”. Il Responsibility-Driven Design è un metodo di design che si
focalizza sugli oggetti come astrazioni comportamentali caratterizzate da
responsabilità, e migliora l’incapsulazione utilizzando un modello client-server.
Per creare le astrazioni comportamentali sì utilizzano comunemente le CRC-
card.
Applicare le responsabilità di un oggetto include: fare qualcosa da solo, come
creare un oggetto o effettuare calcoli; inizializzare un azione in altri oggetti;
controllare e coordinare attività in altri oggetti.
GRASP (General Responsibility Assignment Software Patterns) è una collezione
di pattern, usata nella progettazione object-oriented, che fornisce delle linee
guida per l'assegnazione di responsabilità alle classi e agli oggetti.
Ogni pattern illustra un problema che può verificarsi continuamente nel nostro
ambiente, e descrive il cuore della soluzione al problema, in modo tale che possa
essere usata sempre. I pattern sono: Creator, Information Expert, Low Coupling,
Controller, High Cohesion, Polymorphism, Pure Fabrication, Indirection,
Protected Variations.
Creator: risolve il problema di chi debba essere responsabile per la creazione di
una nuova istanza di una classe. Date due classi A e B, B potrebbe essere
responsabile per la creazione di A nel caso in cui B contenga (o nel complesso
aggreghi, registri, usi strettamente e contenga) le informazioni iniziali per A.
Information Expert: permette di assegnare correttamente le responsabilità agli
oggetti. Stabilisce che la responsabilità deve essere assegnata all'Information
Expert (la classe che possiede tutte le informazioni essenziali). Migliora
l’'incapsulamento e riduce così l'accoppiamento di altre classi per
l'implementazione della classe Information Expert.
Low Coupling: (accoppiamento: grado con cui ciascuna componente di un
software dipende dalle altre componenti) è un pattern valutativo, che stabilisce
come assegnare le responsabilità per supportare: bassa dipendenza tra classi;
basso impatto in una classe dei cambiamenti in altre classi; e alto potenziale di
riuso.
Controller: assegna la responsabilità di eventi di chiamata a sistema ad una classe
(che non sia ad interfaccia utente) che rappresenta l'intero sistema in uno
scenario di caso d'uso. Un controllore di casi d'uso potrebbe essere impiegato
per comunicare con tutti gli eventi di sistema di uno o più casi d'uso (ad esempio,
per i casi d'uso Crea Utente ed Elimina Utente, si può usare un solo controllore
ControlloreUtente, anziché due separati per ciascun caso d'uso).
High Cohesion: (coesione: misura di quanto strettamente correlate siano le varie
funzionalità messe a disposizione da un singolo modulo) è un pattern valutativo
che cerca di mantenere gli oggetti focalizzati, gestibili e intelligibili in maniera
appropriata. Un'alta coesione significa che le responsabilità di un dato elemento
sono fortemente correlate ed altamente focalizzate.
Polymorphism: la responsabilità di definizione delle variazioni dei
comportamenti basati sul tipo viene assegnata ai tipi per i quali avviene tale
variazione. Ciò viene ottenuto usando le operazioni di polimorfismo.
Pure Fabrication: è una classe che non rappresenta un concetto nel dominio del
problema. Ma viene creata per ottenere basso accoppiamento, alta coesione e
potenziale di riuso da esso derivante (quando non vi è
una soluzione presentata dal pattern Information
Expert).
Indirection: supporta il basso accoppiamento (ed il
potenziale di riuso) tra due elementi attraverso
l'assegnazione di responsabilità di mediazione tra di
loro ad un oggetto intermedio. Un esempio è
l'introduzione di un componente controllore per la
mediazione tra i dati (modello) e la loro
rappresentazione (vista) nel pattern Model-View-
Controller.
Protected Variations: protegge gli elementi dalle variazioni compiute in altri
elementi (oggetti, sistemi, sottosistemi) mascherandoli con un'interfaccia ed
usando il polimorfismo per creare diverse implementazioni di questa interfaccia.
Design Patterns
La Gang of Four (GoF) indica che i patterns possono avere 3 scopi:
Creazionali: astraggono il processo di istanziazione - Abstract Factory, Builder,
Factory Method, Prototype, Singleton.
Strutturali: sono legati a come le classi e gli oggetti sono composti per formare
strutture più grandi - Adapter, Bridge, Composite, Decorator, Facade, Flyweight,
Proxy.
Comportamentali: sono legati agli algoritmi e l’assegnamento di responsabilità
tra oggetti - Chain of Responsibility, Command, Interpreter, Iterator, Mediator,
Memento, Observer, State, Strategy, Template Method, Visitor.
Considerazione: composizione invece di ereditarietà
Le due tecniche più comuni per riutilizzare funzionalità nei sistemi object-
oriented sono l’ereditarietà tra classi e la composizione di oggetti (combinare
oggetti semplici o tipi di dato in oggetti più complessi). Favorire la composizione
di oggetti all’ereditarietà tra classi aiuta a mantenere ogni classe incapsulata e
concentrata su un compito. La delegazione è un modo di rendere la
composizione tanto potente per il riuso quanto l’ereditarietà.
Il problema dell’ereditarietà è che non viene affrontato in modo
corretto né l’Open/Closed Principle (OCP) né Protected
Variations (PV). Tuttavia si deve sapere che le superclassi non
sono l’unica astrazione possibile, ed è possibile utilizzare la
composizione, che è più flessibile e può cambiare a runtime.
Template Method [Pattern Comportamentale]
Questo pattern permette di definire la struttura di
un algoritmo lasciando alle sottoclassi il compito di
implementarne alcuni passi come preferiscono. In
questo modo si può ridefinire e personalizzare
parte del comportamento nelle varie sottoclassi
senza dover riscrivere più volte il codice in comune.
Normalmente sono le sottoclassi a chiamare i
metodi delle classi genitrici; in questo pattern è il
metodo template, appartenente alla classe genitrice, a chiamare i metodi
specifici ridefiniti nelle sottoclassi. Tale pattern aiuta
ad adempiere all’OCP.
Strategy [Pattern Comportamentale]
L'obiettivo di questa architettura è isolare un
algoritmo all'interno di un oggetto, in maniera tale da
risultare utile in quelle situazioni dove sia necessario
modificare dinamicamente gli algoritmi utilizzati da
un'applicazione.
Si pensi ad esempio alle possibili visite in una struttura
ad albero (visita anticipata, simmetrica, posticipata);
mediante il pattern strategy è possibile selezionare a tempo
di esecuzione una tra le visite ed eseguirla sull'albero per
ottenere il risultato voluto. Tale pattern aiuta ad
implementare OCP e obbedisce alle PV, inoltre favorisce la
composizione rispetto all’ereditarietà (has-a invece di is-a).
Considerazione: il New è considerato dannoso
Il New alloca memoria ogni volta che un client ha bisogno di una referenza, non
c’è controllo sul ciclo di vita delle istanze e crea una dipendenza tra l’utente e la
classe concreta implementata dalla referenza (viola il Dependency Inversion
Principle - DIP). Inoltre le modifiche nel costruttore della classe concreta creano
problemi nei client (viola l’OCP).
Factory Method [Pattern Creazionale]
Questo pattern indirizza il problema della
creazione di oggetti senza specificarne l'esatta
classe. Questo pattern raggiunge il suo scopo
fornendo un'interfaccia per creare un oggetto,
ma lascia che le sottoclassi decidano quale
oggetto istanziare.
Considerazione: il problema delle notifiche
Nuovi osservatori (e nuovi tipi di osservatori) possono apparire in un tempo
futuro. Quando una classe “notifica” un’altra è esposta alla sua interfaccia
(quindi dipende da quell’interfaccia).
Observer [Pattern Comportamentale]
Sostanzialmente il pattern si basa su uno o più oggetti,
chiamati osservatori o observer, che vengono registrati
per gestire un evento che potrebbe essere generato
dall'oggetto "osservato", che può essere chiamato
soggetto. Oltre all'observer esiste il concrete Observer
che si differenzia dal primo perché implementa
direttamente le azioni da compiere in risposta ad un
messaggio; riepilogando il primo è una classe astratta, il
secondo no. Uno degli aspetti fondamentali è che tutto il
funzionamento dell'observer si basa su meccanismi di
callback, a cui spesso vengono passati dei parametri in fase di
generazione dell'evento.
Façade [Pattern Strutturale]
Significa "facciata", ed infatti indica un oggetto che
permette, attraverso un'interfaccia più semplice,
l'accesso a sottosistemi che espongono interfacce
complesse e molto diverse tra loro, nonché a blocchi di
codice complessi. Fornisce un’interfaccia unificata ad un
insieme di interfacce di un sottosistema: definisce
un’interfaccia a livello più alto che rende il sottosistema
più facile da utilizzare. Nelle librerie standard Java (Java
2 Platform, Standard Edition) questo pattern viene spesso
usato; si considerino ad esempio tutte le classi disponibili
per fare il rendering del testo o delle forme geometriche,
un programmatore può ignorare tutte queste classi e utilizzare unicamente le
classi façade (Font e Graphics) che offrono un'interfaccia più semplice e
omogenea.
Singleton [Pattern Creazionale]
È un pattern che ha lo scopo di garantire che di una
determinata classe venga creata una e una sola istanza, e di
fornire un punto di accesso globale a tale istanza.
L'implementazione più semplice di questo pattern prevede
che la classe singleton abbia un unico costruttore privato, in
modo da impedire l'istanziazione diretta della classe
(fornisce anche un metodo "getter" statico che restituisce l'istanza della classe).
Proxy [Pattern Strutturale]
Nella sua forma più generale, un proxy è una classe che
funziona come interfaccia per qualcos'altro. L'altro
potrebbe essere qualunque cosa: una connessione di
rete, un grosso oggetto in memoria, un file e altre risorse
che sono costose o impossibili da duplicare. Tipicamente
viene creata un'istanza di oggetto complesso, e
molteplici oggetti proxy, ognuno dei quali contiene un
riferimento al singolo oggetto complesso. Ogni
operazione svolta sui proxy viene trasmessa all'oggetto