Vai alla Home Page About me Courseware Federica Living Library Federica Federica Podstudio Virtual Campus 3D Le Miniguide all'orientamento Gli eBook di Federica La Corte in Rete
 
I corsi di Scienze Matematiche Fisiche e Naturali
 
Il Corso Le lezioni del Corso La Cattedra
 
Materiali di approfondimento Risorse Web Il Podcast di questa lezione

Sergio Di Martino » 11.Object Design e Design Patterns


Obiettivi della lezione

Comprendere le attività dell’Object Design

  • Differenze tra System ed Object Design
  • Definizione di Design Patterns
  • Analisi di alcuni Design Patterns
    • Singleton
    • Composite
    • Observer

Software Lifecycle Activities


Object Design

L’Object Design è la fase nel ciclo di vita del software in cui si definiscono le scelte finali prima dell’implementazione.
In questa fase, l’analista deve scegliere tra i differenti modi di implementare i modelli di analisi, rispettando requisiti non funzionali e criteri di design.

Si specificano quali classi implementeranno le funzionalità descritte in analisi, come comincheranno tra loro, etc…

E’ il passo finale di progettazione prima di iniziare l’implementazione

Obiettivi:

  • definizione completa delle relazioni;
  • definizione completa delle classi (System Design => Service, Object Design => API);
  • specifica dei contratti per ogni componente;
  • identifiazione di possibili riusi di componenti esistenti;
  • ottimizzazioni;
  • packaging;

Architetture e Design Patterns

L’attenzione quindi si sposta ad un livello di granularità più fine rispetto al System Design.

Nel System Design, le architetture permettono di “non reinventare la ruota” ogni volta, potendo contare su una sorta di “catalogo” di soluzioni note in letteratura.
Le Architetture sono un modo per definire la struttura di un’applicazione ad alto livello.

  • Definiamo aggregazioni di (molte) classi in ogni modulo che compone l’architettura.
  • Grazie alle architetture già definite, abbiamo una vasta scelta di soluzioni largamente testate per una grande classe di problemi.

Esiste qualcosa simile a livello più basso?
Ci sono modi “”tandard” di combinare classi tra loro per svolgere funzionalità tipiche, che si incontrano spesso durante la fase di design?
→ Design Patterns!

Cos’è un Design Pattern?

Un Design Pattern

  • È una soluzione tipica ad un problema di design ricorrente;
  • astrae una struttura di design;
  • comprende classi e/o oggetti, in termini di:
    • dipendenze;
    • strutture;
    • interazione;
    • convenzioni di naming;
  • è utile per dare un nome esplicito ad uno schema progettuale;
  • è un “distillato” di esperienze di progettazione.

Storia dei Design Patterns

  • Origini nel campo dell’architettura edilizia, da parte di Christopher Alexander.
  • Alexander nota che nella costruzione di edifici ci sono problemi progettuali ricorrenti.
  • Descrive le migliori soluzioni note nel libro “A Pattern Language” (1977).

A metà anni ‘90, la “Gang of Four” (4 tra i più noti ingegneri del software dell’epoca), riportano gli stessi concetti all’informatica, pubblicando il libro “Design Patterns: Elements of Reusable Object-Oriented Software” (1995), che è una sorta di catalogo di soluzioni tipiche di design.
Da allora sono stati scritti molti altri libri sui Design Patterns.

Cos’è un Design Pattern?

Un Design Pattern ha 4 componenti di base:

  1. il Nome;
  2. il Problema che intende affrontare;
  3. la Soluzione proposta;
  4. conseguenze e trade-off della sua applicazione.

I Design Patterns sono tipicamente Language- e implementation-independent.
Non c’è una loro applicazione “meccanica” o automatica.
La soluzione descritta deve essere tradotta dallo sviluppatore in termini concreti nel contesto dell’applicazione da realizzare
L’applicazione di un design pattern ha delle conseguenze, che vanno valutate volta per volta (es: miglioramento della qualità interna del codice a discapito delle performance).

Obiettivi

I Design Patterns hanno l’obiettivo di:

  • codificare del buon design:
    • distillare e disseminare esperienze di progettazione;
    • valido aiuto sia per principianti che per designer esperti;
    • forniscono un’astrazione su come pensare quando si fa design;
  • dare dei nomi espliciti a degli schemi di progettazione:
    • vocabolario comune;
    • maggiore espressività;
    • complessità dello schema ridotta ai punti salienti;
  • catturare e conservare informazioni sul design adottato:
    • migliora la documentazione progettuale di un sistema;
  • facilitiano la manutenzione futura:
    • aggiungono flessibilità al design.

Classificazione dei GoF Design Pattern


Singleton (Creational)

Obiettivo
Assicurarsi che una classe abbia sempre una sola istanza, fornendone un punto di accesso globale.
Applicabilità
Quando ci deve essere una istanza di una classe, e deve essere accessibile da un punto di accesso noto.
Conseguenze

  • Riduce il “namespace pollution” (non ci sono variabili globali).
  • E’ facile da estendere per avere un numero prefissato di istanze.
  • Permette l’estendibilità attraverso sottoclassi.
  • L’implementazione può essere meno efficiente di una variabile globale.
  • Non c’è una gestione esplicita della concorrenza.

Soluzione
Utilizzo di istanze statiche.


Singleton – Esempio di codice****

public class SingolaIstanza {

private static SingolaIstanza istanza = null;

private SingolaIstanza () {}

 public static SingolaIstanza getInstance()

 {

if (istanza == null)

istanza = new SingolaIstanza ();

return istanza;

}

}

Sebbene questo codice gestisca una singola istanza, è molto semplice modificare il metodo getIstance() per avere un numero prefissato di instanze.

Composite (Structural)

Obiettivo
Trattare in maniera omogenea oggetti singoli e multipli, definiti in maniera ricorsiva (es. Nodi e foglie di un albero)

Applicabilità
La struttura deve essere composta ricorsivamente
Deve esserci una funzionalità non distinguibile a livello di signature tra elementi singoli e contenitori
Tutti gli oggetti nella struttura devono essere trattati uniformemente

Conseguenze
Uniformità: trattare i contenitori come nodi, indipendentemente dalla loro complessità
Estensibilità: Oggetti foglia possono essere sostituiti con oggetti contenitori
Overhead: introduce strutture in più di gestione

Soluzione
Un’interfaccia uniforme per foglie e contenitori.

Schema del Composite.

Schema del Composite.

Esempio di struttura gestibile da Composite.

Esempio di struttura gestibile da Composite.


Composite Implementation

Mostra codice

Observer (Behavioral)

Obiettivo
Definire una relazione di dipendenza uno-a-molti tra oggetti, in modo che quando un oggetto cambia stato, tutti quelli che ne sono dipendenti vengono notificati e si aggiornano di conseguenza.

Applicabilità
Quando un cambiamento nello stato di un oggetto richiede delle operazioni in altri oggetti dipendenti, e non si sa a priori quanti saranno gli oggetti da aggiornare
Quando un oggetto deve notificare dei cambiamenti ad altri, senza fare assunzioni sulla struttura di questi altri

Struttura dell’observer.

Struttura dell'observer.


Observer (Behavioral)

Conseguenze
Modularità: subject e observers possono variare indipendentemente
Estendibilità: è possibile aggiungere un qualunque numero di observers
Personalizzazione: differenti observers possono fornire viste differenti dello stato del subject
Aggiornamenti inaspettati: gli observers non si conoscono a vicenda

Soluzione
Subject-observer mapping
C’è il pericolo di avere delle dangling references

Struttura dell’observer.

Struttura dell'observer.


Observer

Esempio di Struttura dell’Observer che sfrutta interfacce per migliorare il disaccoppiamento. Il codice è mostrato nelle slides successive.

Esempio di Struttura dell'Observer che sfrutta interfacce per migliorare il disaccoppiamento. Il codice è mostrato nelle slides successive.


Observer – Subject Interface

// ISubject --> interface for the subject
public interface ISubject {

// Registers an observer to the subject's notification list
void RegisterObserver(IObserver observer);

// Removes a registered observer from the subject's notification list
void UnregisterObserver(IObserver observer);

// Notifies the observers in the notification list of any change that occurred in the subject
void NotifyObservers();
}

Observer – Observer Interface

// IObserver --> interface for the observer
public interface IObserver {

// called by the subject to update the observer of any change
// The method parameters can be modified to fit certain criteria
void Update();
}

Observer – Subject Impl

// Subject --> class that implements the ISubject interface....
using System.Collections;
public class Subject : ISubject {

// use array list implementation for collection of observers
private ArrayList observers;
// decoy item to use as counter

private int counter;
// constructor public Subject() {
observers = new ArrayList();
counter = 0;
}

public void RegisterObserver(IObserver observer)
{
// if list does not contain observer, add
if(!observers.Contains(observer))

{ observers.Add(observer); }

}

Observer – Subject Impl

Mostra codice

Observer – Observer Implementation

// Observer --> Implements the IObserver
public class Observer : IObserver {
// this will count the times the subject changed
// evidenced by the number of times it notifies this observer
private int counter;

public Observer() {

counter = 0;

}
// counter is incremented with every notification
public void Update() {

counter += 1;

}
// a getter for counter
public int Counter {

get { return counter; }

}
}

Riassumendo

I design pattern sono delle soluzioni ben note a problemi di design ricorrenti.
Si dividono in 3 categorie.

1. Strutturali
Focus: Come comporre oggetti per creare strutture più ampie e complesse
Tipi di problemi da risolvere:

  • realizzare nuove funzionalità da vecchie preesistenti;
  • fornire flessibilità ed estendibilità.

2. Behavioral Patterns
Focus: Algoritmi e/o assegnamento di responsabilità ad oggetti.
Tipi di problemi da risolvere :

  • disaccoppiare il resto del sistema da dettagli specifici su come un algoritmo viene implementato.

3. Creational Patterns
Focus: Creazione di oggetti con proprietà complesse.
Tipi di problemi da risolvere:

  • nascondere al resto del sistema come gli oggetti sono creati e messi insieme.

Osservazioni

Evitare l’errore di abusare di Design Pattern.
E’ assolutamente errato pensare che quanti più Design Pattern si usino, tanto più il sistema è progettato bene.
E’ fondamentale capire anche quando NON usare dei Design Patterns.

  • Ogni Pattern ha dei trade-off, che vanno valutati attentamente
  • La maggior parte dei Pattern porta ad una complicazione del design, con più classi, più messaggi, meno efficienza

NON usare un Design Pattern, a meno che non sia effettivamente ciò che serve a risolvere un determinato problema.
Prima essere certi di avere un problema, poi cercare il Pattern che lo può risolvere, non il contrario.

I materiali di supporto della lezione

A Pattern Language, Alexander; Oxford, 1977; ISBN 0-19-501-919-9

Design Patterns, Gamma, et al.; Addison-Wesley, 1995; ISBN 0-201-63361-2; CD version ISBN 0-201-63498-8

Pattern-Oriented Software Architecture, Buschmann, et al.; Wiley, 1996; ISBN 0-471-95869-7

Analysis Patterns, Fowler; Addison-Wesley, 1996; ISBN 0-201-89542-0

Smalltalk Best Practice Patterns, Beck; Prentice Hall, 1997; ISBN 0-13-476904-X

The Design Patterns Smalltalk Companion, Alpert, et al.; Addison-Wesley, 1998; ISBN 0-201-18462-1

AntiPatterns, Brown, et al.; Wiley, 1998; ISBN 0-471-19713-0

  • Contenuti protetti da Creative Commons
  • Feed RSS
  • Condividi su FriendFeed
  • Condividi su Facebook
  • Segnala su Twitter
  • Condividi su LinkedIn
Progetto "Campus Virtuale" dell'Università degli Studi di Napoli Federico II, realizzato con il cofinanziamento dell'Unione europea. Asse V - Società dell'informazione - Obiettivo Operativo 5.1 e-Government ed e-Inclusion