Design Pattern Creazionali
Total Page:16
File Type:pdf, Size:1020Kb
DESIGN PATTERN CREAZIONALI DESIGN PATTERN CREAZIONALI INGEGNERIA DEL SOFTWARE Università degli Studi di Padova Dipartimento di Matematica Corso di Laurea in Informatica, A.A. 2017 – 2018 Architetturali [email protected] Model view controller Ingegneria del software Riccardo Cardin 2 INTRODUZIONE SINGLETON Scopo dei design pattern creazionali Scopo Assicurare l’esistenza di un’unica istanza di una classe Rendere un sistema indipendente … ed avere un punto di accesso globale a questa dall’implementazione concreta delle sue componenti Si nascondono i tipi concreti delle classi realmente utilizzate Motivazione Si nascondono i dettagli sulla composizione e creazione Alcune entità NON DEVONO avere più di un’istanza Riduzione accoppiamento e flessibilità Non è possibile utilizzare una variabile globale (C++) La classe deve tenere traccia della sua unica istanza Ampio uso dell’astrazione / interfacce Ingegneria del software Riccardo Cardin 3 Ingegneria del software Riccardo Cardin 4 SINGLETON SINGLETON Applicabilità Struttura /* * Implementazione Java Definisce getInstance che permette * "naive" */ l’accesso all’unica istanza. È Deve esistere una e una sola istanza di una classe in public class Singleton { responsabile della creazione dell’unica private static tutta l’applicazione istanza Singleton instance; L’istanza deve essere accessibile dai client in modo noto private Singleton() { /* Corpo vuoto */ } L’istanza deve essere estendibile con ereditarietà public static Singleton getInstance() { I client non devono modificare il proprio codice if (instance == nul) { instance = new Singleton(); } return instance; } } Ingegneria del software Riccardo Cardin 5 Ingegneria del software Riccardo Cardin 6 SINGLETON SINGLETON Conseguenze Esempio Esempio Controllo completo di come e quando i client Un applicativo deve istanziare un oggetto che gestisce una accedono all’interfaccia stampante (printer spooler). Questo oggetto deve essere unico perché Evita il proliferare di variabili globali (C++) si dispone di una sola risorsa di stampa. Permette la ridefinizione delle operazioni definite nel Singleton Può permettere un numero massimo e preciso di istanze attive Più flessibile delle operazioni di classe Utilizzo del polimorfismo Ingegneria del software Riccardo Cardin 7 Ingegneria del software Riccardo Cardin 8 SINGLETON SINGLETON Esempio Implementazione Printer Spooler Assicurare un’unica istanza attiva (lazy initialization) Si rende il/i costruttore/i privato/i (non accessibili) Si rende disponibile un’operazione di classe di “recupero” Non è possibile utilizzare variabili globali (C++) Non garantisce l’unicità dell’istanza L’istanza è generata durante l’inizializzazione “statica” L’appoccio non è thread safe in Tutti i singleton sarebbero costruiti sempre, anche se mai Java: nessuna sincronizzazione utilizzati sulla creazione di instance Ingegneria del software Riccardo Cardin 9 Ingegneria del software Riccardo Cardin 10 SINGLETON SINGLETON Soffrono di attacco per Reflection sul costruttore Implementazione Implementazione Ereditare da una classe Singleton Java Costruttore privato (omesso per spazio) public class PrinterSpooler { È difficile installare l’unica istanza nel membro instance private static final PrinterSpooler INSTANCE = new PrinterSpooler(); public static PrinterSpooler getInstance() { La soluzione migliore è utilizzare un registro di singleton return INSTANCE; public class Singleton { } private static Singleton instance; } private static Map<String, Singleton> registry; public class MySingleton no lazy, thread safe, no subclassing, no serializable extends Singleton { private Singleton() { /* Corpo vuoto */ } public class PrinterSpooler { static { public static register(String name, Singleton) private static volatile PrinterSpooler INSTANCE; { /* ... */} Singleton.register(“MySingleton”, public static PrinterSpooler getInstance() { new MySingleton()) if (INSTANCE == null) { protected static Singleton lookup(String name) } synchronize (PrinterSpooler.class) { { /* ... */} /* ... */ if (INSTANCE == null { INSTANCE = new PrinterSpooler(); } public static Singleton } } getInstance(String singletonName) { } return INSTANCE; /* Utilizza lookup per recuperare l’istanza */ } } } } lazy, thread safe, subclassing possibile, no serializable Ingegneria del software Riccardo Cardin 11 Ingegneria del software Riccardo Cardin 12 SINGLETON SINGLETON Cons: meno Implementazione Implementazione controllo sull’inizializzazione Java Scala object PrinterSpooler extends ... { Versione accettata da JDK ≥ 1.5 def print(file: String) { public enum PrinterSpooler { // do something INSTANCE; } } public void print(String file) { /* ... */ } } In Java il pattern Sigleton è uno dei più utilizzati no lazy, thread safe, no subclassing, serializable Mancanza a livello di linguaggio Item 3 di Effective Java di Joshua Bloch Error prone Usa costrutti nativi del linguaggio Scala risolve introducendo il tipo object Non soffre di alcun attacco Implementazione del pattern Singleton nel linguaggio Conciso, leggibile e manutenibile Thread‐safe Gli Object sono inizializzati su richiesta (laziness) Ingegneria del software Riccardo Cardin 13 Ingegneria del software Riccardo Cardin 14 SINGLETON BUILDER Implementazione Scopo Javascript: si utilizza il module pattern Private Separa la costruzione di un oggetto complesso dalla namespace var mySingleton = (function () { var instance; sua rappresentazione function init() { // Private methods and variables function privateMethod() { console.log( "I am private" ); }; Motivazione var privateRandomNumber = Math.random(); Necessità di riutilizzare un medesimo algoritmo di return { // Public methods and variables costruzione per più oggetti di tipo differente publicMethod: function () { console.log( "The public can see me!" ); Processo di costruzione step‐by‐step }, getRandomNumber: function() { return privateRandomNumber; } }; Il cassiere deve: }; return { 1. Inserire il panino getInstance: function () { Public 2. Inserire le patate if ( !instance ) { instance = init(); } return instance; functions/variables 3. Inserire la frutta } 4. ... }; })(); Ingegneria del software Riccardo Cardin 15 Ingegneria del software Riccardo Cardin 16 BUILDER BUILDER Esempio Applicabilità La procedura di creazione di un oggetto complesso deve essere indipendente dalle parti che compongono l’oggetto Il processo di costruzione deve permettere diverse rappresentazioni per l’oggetto da costruire Ingegneria del software Riccardo Cardin 17 Ingegneria del software Riccardo Cardin 18 BUILDER BUILDER Struttura Struttura Costruisce un oggetto Specifica l’interfaccia da utilizzando il builder utilizzare per assemblare Il client conosce il tipo (procedura) il prodotto builder concreto Il director notifica il builder delle parti che devono essere costruite Il prodotto complesso da costruire Costruisce e assembla le parti del Il client recupera dal prodotto. Tiene traccia dell’istanza builder concreto il costruita. Fornisce un’interfaccia per prodotto finito recuperare il prodotto finale Ingegneria del software Riccardo Cardin 19 Ingegneria del software Riccardo Cardin 20 BUILDER BUILDER Conseguenze Esempio Facilita le modifiche alla rappresentazione interna di Si vuole ordinare un bicchiere di scotch. È necessario fornire al un prodotto barman alcune informazioni: la marca del whiskey, come deve essere È sufficiente costruire un nuovo builder: NO telescoping! preparato (liscio, on the rocks, allungato) e se lo si desidera doppio. È inoltre possibile scegliere il tipo di bicchiere (piccolo, lungo, a Isola il codice dedicato alla costruzione di un prodotto tulipano). dalla sua rappresentazione Il client non conosce le componenti interne di un prodotto [se fossimo veramente intenditori, anche la marca e la temperatura Encapsulation dell’acqua sarebbero fondamentali...] L’orchestrazione dei processi di costruzione è unica Consente un controllo migliore del processo di costruzione Costruzione step‐by‐step Accentramento logica di validazione Ingegneria del software Riccardo Cardin 21 Ingegneria del software Riccardo Cardin 22 BUILDER BUILDER Implementazione Il builder defisce un’interfaccia per ogni parte che il director può richiedere di costruire Abbastanza generale per la costruizione di prodotti differenti Appending process Nessuna classe astratta comune per i prodotti Differiscono notevolmente fra loro Se simili, valutare l’utilizzo di un Abstract Factory Pattern Fornire metodi vuoti come default I builder concreti ridefiniscono solo i metodi necessari Ingegneria del software mod. A Riccardo Cardin 23 Ingegneria del software Riccardo Cardin 24 BUILDER BUILDER Implementazione Implementazione Java: il builder diventa classe interna del prodotto Java public class OrderOfScotch { // CONTINUA... private String brand; public OrderOfScotch build() { return new OrderOfScotch(this); } private Praparation preparation; // Si puo’ dichiarare enum interna } // public static class Builder // ... private OrderOfScotch() { } // Costruttore privato per il prodotto public static void main(String[] args) { private OrderOfScotch(Builder builder) { // Il client non conosce il processo di costruzione e le classi this.brand = builder._brand; // prodotto e builder sono correttamente accoppiate tra loro. // ... // Non e’ possibile costruire un prodotto se non con il builder. } OrderOfScotch oos = new OrderOfScotch.Builder() public static class Builder { .setBrand(“Brand 1“) private String