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 (++)

 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 ()  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 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 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  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 $( '

bar
' ); return this; // Append behaviour }, $( '

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

, 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 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 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