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
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 _brand; // Inserisco '_' per diversificare .setPreparation(NEAT) private Praparation _preparation; // ... // ... .build(); public ScotchBuilder setBrand(String brand) { } this._brand = brand; } // public class OrderOfScotch return this; // Appending behaviour } // CONTINUA... Item 2 di Effective Java di Joshua Bloch Ingegneria del software Riccardo Cardin 25 Ingegneria del software Riccardo Cardin 26
BUILDER BUILDER
Implementazione Implementazione Javascript Javascript – JQuery Approccio classico, var Builder = function() { Costruzione step‐by‐step del DOM var a = "defaultA"; // Valori default con l’utilizzo degli var b = "defaultB"; scope per la // I metodi appendTo, attr, text permettono di costruire un oggetto return { creazione degli // all’interno del DOM in modo step-by-step withA : function(anotherA) { a = anotherA; oggetti $( '
foo bar
').appendTo("body"); withB : function(anotherB) { b = anotherB; var newParagraph = $( "" ).text( "Hello world" ); return this; }, $( "" ) build : function() { .attr({ "type": "text", "id":"sample"}) return "A is: " + a +", B is: " + b; .appendTo("#container"); } }; }; var first = builder.withA().withB("a different value for B").build(); Ingegneria del software Riccardo Cardin 27 Ingegneria del software Riccardo Cardin 28 BUILDER ABSTRACT FACTORY Implementazione Scopo Fornisce un’interfaccia per creare famiglie di prodotti Scala senza specificare classi concrete In Scala è possibile utilizzare i principi dei linguaggi funzionali Motivazione Immutabilità del builder Applicazione configurabile con diverse famiglie di Type‐safe builder componenti Assicura staticamente che sono state fornite tutte le Toolkit grafico informazioni necessarie alla costruzione Si definisce una classe astratta factory che definisce le Si utilizzano feature avanzate del linguaggio interfacce di creazione. Type constraints I client non costruiscono direttamente i “prodotti” http://blog.rafaelferreira.net/2008/07/type‐safe‐builder‐ Si definiscono le interfacce degli oggetti da creare pattern‐in‐scala.html Le classi che concretizzano factory vengono costruite una http://www.tikalk.com/java/type‐safe‐builder‐scala‐using‐ type‐constraints/ volta sola
Ingegneria del software Riccardo Cardin 29 Ingegneria del software Riccardo Cardin 30
ABSTRACT FACTORY ABSTRACT FACTORY
Applicabilità Struttura Dichiara l’interfaccia di Interfaccia per creazione dei prodotti un particolare Un sistema indipendente da come i componenti sono prodotto creati, composti e rappresentati
Un sistema configurabile con più famiglie prodotti
Le componenti di una famiglia DEVONO essere utilizzate insieme
Costruiscono i Si vuole fornire una libreria di classi prodotto, senza prodotti concreti rivelarne l’implementazione. Definisce un prodotto concreto, che deve essere costruito mediante factory Ingegneria del software Riccardo Cardin 31 Ingegneria del software Riccardo Cardin 32 ABSTRACT FACTORY ABSTRACT FACTORY
Conseguenze Esempio
Esempio Isolamento dei tipi concreti Si vuole realizzare un negozio di vendita di sistemi Hi-Fi, dove si I client manipolano unicamente interfacce, i nomi dei eseguono dimostrazioni dell’utilizzo dei prodotti. prodotti sono nascosti Semplicità maggiore nell’utilizzo di una diversa Esistono due famiglie di prodotti, basate su tecnologie diverse: - supporto di tipo nastro (tape) famiglia di prodotti - supporto di tipo digitale (CD). La factory concreta appare solo una volta nel programma Ogni famiglia è composta da: Promuove la consistenza fra i prodotti - supporto (tape o CD) Difficoltà nel supportare nuovi prodotti - masterizzatore (recorder) - riproduttore (player). Modificare l’interfaccia della factory astratta costringe il cambiamento di tutte le sotto classi.
Ingegneria del software Riccardo Cardin 33 Ingegneria del software Riccardo Cardin 34
ABSTRACT FACTORY ABSTRACT FACTORY
Esempio Esempio Scala: companion object (Factory Method)
trait Animal private class Dog extends Animal private class Cat extends Animal
object Animal { def apply(kind: String) = Equivale a kind match { Animal(...) case "dog" => new Dog() case "cat" => new Cat() } }
val animal = Animal("dog") Apply è tradotto in un simil – costruttore Si utilizza per la costruzione delle factory concrete
Ingegneria del software Riccardo Cardin 35 Ingegneria del software Riccardo Cardin 36 ABSTRACT FACTORY ABSTRACT FACTORY
Esempio Implementazione Javascript: varie tecniche di implementazione var AbstractVehicleFactory = (function () { Solitamente si necessita di una sola istanza della // Storage for our vehicle types var types = {}; factory (Singleton design pattern)
return { getVehicle: function ( type, customizations ) { Definizione di factory estendibili var Vehicle = types[type]; return (Vehicle ? new Vehicle(customizations) : null); Aggiungere un parametro ai metodi di creazione dei prodotti }, Il parametro specifica il tipo di prodotto registerVehicle: function ( type, Vehicle ) { var proto = Vehicle.prototype; Nei linguaggi tipizzati staticamente è possibile solo se tutti if ( proto.drive && proto.breakDown ) { types[type] = Vehicle; i prodotti condividono la stessa interfaccia } Può obbligare a down cast pericolosi … return AbstractVehicleFactory; Registro solamente gli } oggetti che soddisfano }; un contratto (abstract })(); product) Ingegneria del software Riccardo Cardin 37 Ingegneria del software Riccardo Cardin 38
RIFERIMENTI GITHUB REPOSITORY
Design Patterns, Elements of Reusable Object Oriented Software, GoF, 1995, Addison‐Wesley Design Patterns http://sourcemaking.com/design_patterns Java DP http://www.javacamp.org/designPattern/ Exploring the Decorator Pattern in Javascript http://addyosmani.com/blog/decorator‐pattern/ Design Patterns in Scala http://pavelfatin.com/design‐patterns‐in‐scala Item 2: Consider a builder when faced with many constructor parameters http://www.informit.com/articles/article.aspx?p=1216151&seqNum=2 https://github.com/rcardin/swe Item 3: Enforce the singleton property with a private constructor or an enum type http://www.informit.com/articles/article.aspx?p=1216151&seqNum=3 Type‐safe Builder Pattern in Scala http://blog.rafaelferreira.net/2008/07/type‐safe‐builder‐pattern‐in‐ scala.html
Ingegneria del software Riccardo Cardin 39 Ingegneria del software Riccardo Cardin 40