Ingegneria del software e Design Pattern

Ingegneria del software e Design Pattern

I design pattern rappresentano soluzioni già pronte, che permettono di realizzare il principio del riuso, uno dei principi base dell’ingegneria del software, non solo a livello di codice (librerie di classi) ma anche a livello di progettazione, perché abbiamo dei pattern (schemi vuoti) che possono essere adattati allo schema delle classi che vogliamo realizzare.

Attraverso questa tabella possiamo classificare i pattern secondo lo scopo (Creazionali, Strutturali e Comportamentali) e il raggio d’azione (per Classi o per Oggetti). Questi qui sotto elencati sono i più noti e più utilizzati, si veda a tal proposito la tabella seguente.

 

Scopo
Creazionale
Strutturale
Comportamentale
Raggio 
d'azione
Classi
Factory 
method
Adapter
Interpreter
Template Method
Oggetti
Abstarct 
factory
Builder
Prototype
Singleton
Adapter Bridge
Composite Decorator
Facade Flyweight
Proxy
Chain of 
responsibility
Command
Iterator
Mediator
Memento
Observer
State
Strategy
Visitor

Ingegneria del software e Design Pattern
Ingegneria del software e Design Pattern – Tabella riassuntiva

Pattern Strutturali

Partiamo dunque dai pattern STRUTTURALI. Possiamo dire che i pattern strutturali si occupano del problema di come comporre le classi e gli oggetti per formare delle strutture più complesse. Abbiamo sia pattern basati su classi che basati su oggetti. La differenza sta nel fatto che quelli basati su classi le interfacce e le implementazioni vengono composto mediante l’ereditarietà, quelli basati su oggetti descrivono la modalità secondo cui comporre gli oggetti per realizzare nuove funzionalità, ovviamente in questo modo è possibile fornire maggiore flessibilità.

Pattern Adapter

L’Adapter è quello più utilizzato in assoluto poiché fornisce la funzionalità di convertire l’interfaccia di una classe nell’interfaccia di un’altra classe. Supponiamo di avere un editor grafico in grado di comporre disegni ma anche testo. L’incompatibilità sta nel fatto che testo e linee e poligoni sono classi con interfacce diverse e quindi per rendere simili uso l’adapter.

Pattern Bridge e Pattern Proxy

Simili all’adapter vi sono il Bridge, il Proxy e il Decorator. Il Bridge ha come obiettivo quello di separare l’interfaccia dall’implementazione. Disaccoppia l’astrazione dalla sua implementazione. Esso si usa quando non si vuole un legame permanente tra astrazione e implementazione. Se ad esempio voglio poter variare dinamicamente l’implementazione di una classe. Oppure quando voglio estendere sia l’implementazione che l’astrazione usando il meccanismo delle sottoclassi. Per quanto riguarda la struttura si ha una classe astratta con diverse implementazioni di essa, e la classe astrazione che non ha nessuna relazione di ereditarietà con le classi concrete implemenction.

Ingegneria del software e Design Pattern - Struttura Implemenction
Ingegneria del software e Design Pattern – Struttura Implemenction

L’abstraction è l’ interfaccia dell’astrazione che ha un riferimento all’implementor che è il vero e proprio bridge, e definisce le interfacce per le classi implementatrici e non corrisponde totalmente all’interfaccia dell’abstraction perchè deve permettere di eseguire una piuttosto dell’altra tra le implementazioni esistenti .Il concrete implementor definisce le varie implementazioni con la realizzazione completa di un algoritmo piuttosto che un altro.

Esempio:

Supponiamo di implementare un toolkit per interfacce utente in ambiente Windows che permetta di scrivere applicazioni che siano eseguite su piattaforme X o IBM. Se usassimo l’ereditarietà dovremmo stabilire staticamente una sottoclasse per ogni tipo di finestra, e quindi sarebbe piu difficile seguire le applicazioni su piattaforme distinte mentre con l’implementor scelgo se seguire l’implementazione su piattaforma X o IBM.

Si spezza la gerarchia dell’ereditarietà, L’aspetto di implementazione è distinto e gestito da un ulteriore classe.

Pattern Decorator

Il decorator permette di aggiungere dinamicamente responsabilità ad un oggetto, cioè invece di definire delle sottoclassi per estendere delle funzionalità si aggiunge un decorator che aggiunge queste funzionalità. Per aggiungere funzionalità a singoli oggetti e non all’intera classe, e ciò fa capire che si sta parlando di qualcosa che succede a run-time, modifica dell’oggetto dinamicamente. In caso contrario bisognerebbe creare una sottoclasse staticamente appesantendo una struttura di ereditarietà con qualcosa che non sempre sarebbe strettamente necessario. Il decorator ha interfaccia conforme a quella dell’oggetto da estendere in modo di renderlo trasparente al client (ossia a tutto il resto del sistema, le richieste vengono trasferite al componente decorato, l’altra caratteristica è che consente l’aggiunta di un numero “illimitato” di funzionalità e non compromette altre classi.

La struttura ricorda un po’ quella del bridge poiché il decorator fa da tramite tra il componente e la sottoclasse di esso. Fa da tramite per poi selezionare una funzionalità piuttosto che un’altra, dinamicamente.

La struttura del decorator è la seguente:

Ingegneria del software e Design Pattern - Struttura Decorator
Ingegneria del software e Design Pattern – Struttura Decorato

Il Component definisce l’interfaccia comune per gli oggetti ai quali possono essere aggiunte responsabilità dinamicamente, Il concrete Component definisce un oggetto al quale possono essere aggiunte responsabilità ulteriori, il decorator è la sottoclasse che mantiene il riferimento al component e definisce l’interfaccia conforme a quella di component che però faccia da tramite con il concrete decorator, il concrete decorator sono quelle funzionalità che posso aggiungere all’oggetto.

Componente Proxy

Il proxy ha lo scopo di fornire il surrogato o un segnaposto di un altro oggetto per controllare l’accesso a tale oggetto. Quando per esempio in documenti di testo inserisco l’immagine in realtà inserisco un proxy.

La motivazione per cui utilizzare il Proxy è quello di controllare l’accesso a un oggetto. Lo si applica quando si necessita avere riferimento a un oggetto che sia più versatile e raffinato di un semplice puntatore. Il proxy è un oggetto vero e proprio che ha una sua caratterizzazione. Esso può essere remoto,quando fornisce rappresentazione locale di un oggetto in diverso spazio di indirizzamento , virtuale, quando si vuole risparmiare in termini di memoria e di tempo di esecuzione, o un proxy di protezione se voglio controllare l’accesso a un oggetto, quando ad esempio si hanno dei diritti di accesso su un oggetto.

ll Subject è l’interfaccia comune mentre il real subject è l’elemento duplicato dal Proxy.

Ingegneria del software e Design Pattern - Struttura Proxy
Ingegneria del software e Design Pattern – Struttura Proxy

Possiamo quindi arrivare a commentare i pattern strutturali. Essi si basano su un insieme di meccanismi messi a disposizione da linguaggi di programmazione che possono risolvere problemi di implementazione di aggiunta di funzionalità e cosi via, a run time. Solo nel caso dell’adapter il problema viene risolto staticamente. I meccanismi sono quelli di composizione tra gli oggetti.

Pattern Comportamentali

Pattern Observer e Pattern Strategy

La seconda categoria di pattern sono quelli COMPORTAMENTALI di cui studieremo l’Observer e lo Strategy.

Essi in generale si occupano di come attribuire le responsabilità ad oggetti che comunicano tra loro, a run time, problemi simili a quelli del Bridge. Quando si hanno flussi di informazioni difficili da seguire, e quando vogliamo studiare le relazioni dinamiche tra oggetti. Quei pochi pattern basati su classi utilizzano l’ereditarietà, mentre quelli su oggetti utilizzano la composizione. Con l’uso dei pattern si riesce a comunicare, modificare e uant altro mantenendo molto basso il livello di accoppiamento.

Pattern Creazionali

I design pattern creazionali astraggono il processo di istanziazione. Più nel dettaglio, essi consentono di rendere il sistema indipendente da come gli oggetti sono creati, rappresentati e delle relazioni di composizione tra essi.

  • Se basati su classi, utilizzano l’ereditarietà per modificare la classe istanziata.
  • Se basati su oggetti, delegano l’istanziazione ad altri oggetti.

Queste due caratteristiche conferiscono una notevole flessibilità al processo di creazione, dal momento che ciò che viene creato in generale risulta essere disaccoppiato dal contesto di utilizzo. Infatti solo l’oggetto creatore conosce il tipo effettivo dell’istanza e ciò che viene esternamente reso pubblico è unicamente l’interfaccia di riferimento. Una delle loro funzioni è appunto quella di permettere l’incapsulamento e la conoscenza relativa alle classi concrete utilizzate dal sistema. Infatti essi permettono di nascondere come le istanze delle classi sono create e assemblate.

Pattern creazionali importanti

Alcuni creational patterns sono i seguenti:

  • Abstract Factory: un oggetto che serve a creare istanze di altri oggetti;
  • Factory Method: un oggetto che serve a creare istanze di diverse classi derivate;
  • Prototype: istanza completa di un oggetto che serve per essere clonato o copiato;
  • Singleton: un oggetto che restituisce una sola istanza di se stesso.

 

Pubblicato da Vito Lavecchia

Lavecchia Vito Ingegnere Informatico (Politecnico di Bari) Email: [email protected] Sito Web: https://vitolavecchia.altervista.org

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *