Articoli

Cosa sono i design patterns: perchè usarli, classificazione, pro e contro

Nell’ingegneria del software, i design pattern sono soluzioni ottimali a problemi che si verificano comunemente nella progettazione del software.

Sono come progetti predefiniti, già provati e testati, che puoi personalizzare per risolvere un problema di progettazione ricorrente nel tuo codice.

Tempo di lettura stimato: 6 minuti

Cos’è un Design Pattern

Un design pattern non è un codice che possiamo copiare e inserire nel nostro programma, come possiamo fare con funzioni o librerie standard. Il design pattern è un concetto generale in grado di risolvere un problema particolare. Praticamente un modello di cui possiamo seguire i dettagli e implementare una soluzione che si adatti alla realtà del nostro programma.

I modelli vengono spesso confusi con gli algoritmi, perché entrambi i concetti descrivono soluzioni tipiche ad alcuni problemi noti. Mentre un algoritmo definisce sempre un insieme chiaro di azioni che possono raggiungere un certo obiettivo, un modello è una descrizione di livello più alto di una soluzione. Il codice dello stesso modello applicato a due programmi diversi potrebbe essere diverso.

Volendo fare un’analogia, possiamo pensare a una ricetta di cucina: entrambi hanno passaggi chiari per raggiungere un obiettivo. Però, un modello è più simile a un progetto, di cui puoi vedere quali sono il risultato e le sue caratteristiche, ma l’ordine esatto di implementazione dipende da noi che scriviamo il codice.

Di cosa è composto un Design Pattern ?

La maggior parte dei modelli sono descritti in modo molto formale in modo che le persone possano riprodurli in molti contesti. Vediamo qui di seguito gli elementi che sono presenti nella descrizione di un modello:

  • L’intento del modello descrive brevemente sia il problema che la soluzione.
  • La motivazione spiega ulteriormente il problema e la soluzione che il modello rende possibile.
  • La struttura delle classi mostra ciascuna parte del modello e come sono correlate.
  • L’esempio di codice in uno dei linguaggi di programmazione più diffusi rende più facile comprendere l’idea alla base del modello.

Perchè usarli ?

Un programmatore può sviluppare software ignorando l’esistenza dei design pattern. Molti lo fanno, e proprio per questo implementano alcuni schemi senza saperlo. Ma allora perché dovremmo dedicare del tempo ad impararli ?

  • I design pattern sono un kit di soluzioni provate e testate a problemi comuni nella progettazione del software. Anche se non incontri mai questi problemi, conoscere i pattern è comunque utile perché ti insegna come risolvere tutti i tipi di problemi utilizzando i principi della progettazione orientata agli oggetti.
  • I modelli di progettazione definiscono un linguaggio comune che tu e il tuo gruppo di lavoro potete utilizzare per comunicare in modo più efficiente. Potresti dire: “Oh, usa semplicemente un Singleton per far questo” e tutti capiranno l’idea alla base del tuo suggerimento. Non c’è bisogno di spiegare cos’è un singleton se conosci lo schema e il suo nome.

Classificazione dei Design Pattern

I modelli di progettazione differiscono per complessità, livello di dettaglio e scala di applicabilità all’intero del sistema progettato.

Per analogia, possiamo rendere più sicuro un incrocio installando alcuni semafori o costruendo un intero svincolo multilivello con passaggi sotterranei per i pedoni.

I modelli più basilari e di basso livello sono spesso chiamati idiomi . Di solito si applicano solo a un singolo linguaggio di programmazione.

I modelli più universali e di alto livello sono i modelli architettonici . Gli sviluppatori possono implementare questi modelli praticamente in qualsiasi linguaggio. A differenza di altri pattern, possono essere utilizzati per progettare l’architettura di un’intera applicazione.

Inoltre, tutti i modelli possono essere classificati in base al loro intento o scopo. L tre classi principali sono:

Articoli correlati
Newsletter sull’Innovazione
Non perderti le notizie più importanti sull'Innovazione. Iscriviti per riceverle via e-mail.
  • I modelli creazionali forniscono meccanismi di creazione di oggetti che aumentano la flessibilità e il riutilizzo del codice esistente.
  • I modelli strutturali spiegano come assemblare oggetti e classi in strutture più grandi, mantenendo queste strutture flessibili ed efficienti.
  • I modelli comportamentali si occupano della comunicazione efficace e dell’assegnazione delle responsabilità tra gli oggetti.

Esempio di Design Pattern in Laravel: Facade

Facade è un modello di progettazione strutturale che fornisce un’interfaccia semplificata a una libreria, un framework o qualsiasi altro insieme complesso di classi.

Problema

Ipotizziamo di avere la necessità di far funzionare un software, basandoci su un ampio insieme di oggetti che appartengono a una libreria o un framework sofisticato. Normalmente, dovremmo inizializzare tutti questi oggetti, tenere traccia delle dipendenze, eseguire i metodi nell’ordine corretto e così via.

Di conseguenza, la logica aziendale delle classi diventerebbe strettamente collegata ai dettagli di implementazione delle classi di terze parti, rendendone difficile la comprensione e la gestione.

Soluzione

Una facade è una classe che fornisce un’interfaccia semplice a un sottosistema complesso che contiene molte parti mobili. Una facade potrebbe fornire funzionalità limitate rispetto al funzionamento diretto con il sottosistema. Tuttavia, include solo le funzionalità che interessano veramente ai clienti.

Avere una facade è utile quando dobbiamo integrare la app con una libreria sofisticata che ha dozzine di funzionalità, ma ci serve solo una piccola parte della sua funzionalità.

Ad esempio, un’app che carica brevi video divertenti con gatti sui social media potrebbe potenzialmente utilizzare una libreria di conversione video professionale. Tuttavia, tutto ciò di cui abbiamo veramente bisogno è una classe con il metodo single encode(filename, format). Dopo aver creato una classe di questo tipo e averla collegata alla libreria di conversione video, avremo la nostra prima facade.

Ad esempio l’operatore telefonico di un call center, è come una facade. Infatti quando telefoniamo al servizio telefonico di un negozio per effettuare un ordine telefonico, un operatore è la nostra facade verso tutti i servizi e i reparti del negozio. L’operatore fornisce una semplice interfaccia vocale al sistema di ordinazione, ai gateway di pagamento e a vari servizi di consegna.

Esempio reale in PHP

Pensa alla Facade come ad un adattatore semplice per alcuni sottosistemi complessi. Facade isola la complessità all’interno di una singola classe e consente ad altro codice applicativo di utilizzare l’interfaccia semplice.

In questo esempio, Facade nasconde la complessità dell’API YouTube e della libreria FFmpeg al codice client. Invece di lavorare con dozzine di classi, il cliente utilizza un metodo semplice su Facade.

<?php

namespace RefactoringGuru\Facade\RealWorld;

/**
 * The Facade provides a single method for downloading videos from YouTube. This
 * method hides all the complexity of the PHP network layer, YouTube API and the
 * video conversion library (FFmpeg).
 */
class YouTubeDownloader
{
    protected $youtube;
    protected $ffmpeg;

    /**
     * It is handy when the Facade can manage the lifecycle of the subsystem it
     * uses.
     */
    public function __construct(string $youtubeApiKey)
    {
        $this->youtube = new YouTube($youtubeApiKey);
        $this->ffmpeg = new FFMpeg();
    }

    /**
     * The Facade provides a simple method for downloading video and encoding it
     * to a target format (for the sake of simplicity, the real-world code is
     * commented-out).
     */
    public function downloadVideo(string $url): void
    {
        echo "Fetching video metadata from youtube...\n";
        // $title = $this->youtube->fetchVideo($url)->getTitle();
        echo "Saving video file to a temporary file...\n";
        // $this->youtube->saveAs($url, "video.mpg");

        echo "Processing source video...\n";
        // $video = $this->ffmpeg->open('video.mpg');
        echo "Normalizing and resizing the video to smaller dimensions...\n";
        // $video
        //     ->filters()
        //     ->resize(new FFMpeg\Coordinate\Dimension(320, 240))
        //     ->synchronize();
        echo "Capturing preview image...\n";
        // $video
        //     ->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(10))
        //     ->save($title . 'frame.jpg');
        echo "Saving video in target formats...\n";
        // $video
        //     ->save(new FFMpeg\Format\Video\X264(), $title . '.mp4')
        //     ->save(new FFMpeg\Format\Video\WMV(), $title . '.wmv')
        //     ->save(new FFMpeg\Format\Video\WebM(), $title . '.webm');
        echo "Done!\n";
    }
}

/**
 * The YouTube API subsystem.
 */
class YouTube
{
    public function fetchVideo(): string { /* ... */ }

    public function saveAs(string $path): void { /* ... */ }

    // ...more methods and classes...
}

/**
 * The FFmpeg subsystem (a complex video/audio conversion library).
 */
class FFMpeg
{
    public static function create(): FFMpeg { /* ... */ }

    public function open(string $video): void { /* ... */ }

    // ...more methods and classes... RU: ...дополнительные методы и классы...
}

class FFMpegVideo
{
    public function filters(): self { /* ... */ }

    public function resize(): self { /* ... */ }

    public function synchronize(): self { /* ... */ }

    public function frame(): self { /* ... */ }

    public function save(string $path): self { /* ... */ }

    // ...more methods and classes... RU: ...дополнительные методы и классы...
}


/**
 * The client code does not depend on any subsystem's classes. Any changes
 * inside the subsystem's code won't affect the client code. You will only need
 * to update the Facade.
 */
function clientCode(YouTubeDownloader $facade)
{
    // ...

    $facade->downloadVideo("https://www.youtube.com/watch?v=QH2-TGUlwu4");

    // ...
}

$facade = new YouTubeDownloader("APIKEY-XXXXXXXXX");
clientCode($facade);

Ercole Palmeri

Newsletter sull’Innovazione
Non perderti le notizie più importanti sull'Innovazione. Iscriviti per riceverle via e-mail.

Leggi Innovazione nella tua Lingua

Newsletter sull’Innovazione
Non perderti le notizie più importanti sull'Innovazione. Iscriviti per riceverle via e-mail.

Seguici