Design patterns: Facade, cos'è e come usarlo (esempio PHP)

data: · 4 min
autore: Mauto
serie: Design Patterns/ parte 11/24

I pattern classici della Gang of Four, uno per puntata, con esempi pratici in PHP.

  1. Design Patterns
  2. Design patterns: Singleton
  3. Design patterns: Factory Method
  4. Design patterns: Abstract Factory
  5. Design patterns: Builder
  6. Design patterns: Prototype
  7. Design patterns: Adapter
  8. Design patterns: Bridge, cos’è e come usarlo (esempio PHP)
  9. Design patterns: Composite
  10. Design patterns: Decorator
  11. Design patterns: Facade, cos’è e come usarlo (esempio PHP)
  12. Design patterns: Flyweight
  13. Design patterns: Proxy
  14. Design patterns: Chain of Responsibility, cos’è (esempio PHP)
  15. Design patterns: Command
  16. Design patterns: Interpreter
  17. Design patterns: Iterator
  18. Design patterns: Mediator
  19. Design patterns: Memento
  20. Design patterns: Observer
  21. Design patterns: State, cos’è e come usarlo (esempio PHP)
  22. Design patterns: Strategy
  23. Design patterns: Template Method
  24. Design patterns: Visitor
tutta la guida >

Il Facade Pattern fornisce un’interfaccia semplificata per un insieme di interfacce in un sistema complesso, rendendo più facile l’uso delle funzionalità del sistema. È particolarmente utile quando si desidera semplificare l’interazione con un sistema o una libreria complessa.

Caratteristiche del Facade Pattern

  1. Interfaccia semplificata: Il Facade Pattern fornisce un’interfaccia semplificata a un sistema complesso o a un insieme di classi, rendendo più facile l’interazione con questi componenti senza dover comprendere i dettagli interni.
  2. Isolamento dal Sistema sottostante: Consente di isolare il client dalle complessità del sistema sottostante, riducendo la dipendenza e migliorando la manutenibilità. I client non devono conoscere le classi specifiche e le loro interazioni.
  3. Facilitazione dell’utilizzo: Rende più semplice e intuitivo utilizzare un sistema complesso, riducendo la curva di apprendimento per gli sviluppatori e migliorando l’esperienza dell’utente.
  4. Supporto per il riuso del codice: Può riunire classi e funzionalità esistenti in un’unica interfaccia, facilitando il riuso del codice e semplificando l’integrazione di nuove funzionalità.
  5. Facilitazione delle modifiche: Consente di apportare modifiche al sistema sottostante senza influenzare il client. Se il sistema viene aggiornato, il client può continuare a utilizzare la facciata senza modifiche.

Esempio in PHP:

Immagina di avere un sistema di gestione di un cinema che gestisce diverse operazioni come la gestione di film, la vendita di biglietti e la gestione degli utenti. Un Facade può semplificare queste interazioni per il codice client.

// Sottosistema: Gestione dei Film
class Movie {
    private $title;
    private $duration; // in minuti

    public function __construct($title, $duration) {
        $this->title = $title;
        $this->duration = $duration;
    }

    public function getTitle() {
        return $this->title;
    }

    public function getDuration() {
        return $this->duration;
    }
}

// Sottosistema: Gestione dei Biglietti
class Ticket {
    private $movie;
    private $seatNumber;

    public function __construct(Movie $movie, $seatNumber) {
        $this->movie = $movie;
        $this->seatNumber = $seatNumber;
    }

    public function getDetails() {
        return "Biglietto per il film '{$this->movie->getTitle()}' al posto {$this->seatNumber}.";
    }
}

// Sottosistema: Gestione degli Utenti
class User {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

// Sottosistema: Catalogo dei Film
class MovieCatalog {
    private $movies = [];

    public function add(Movie $movie) {
        $this->movies[] = $movie;
    }

    public function findByTitle($title) {
        foreach ($this->movies as $movie) {
            if ($movie->getTitle() == $title) {
                return $movie;
            }
        }
        return null;
    }
}

// Sottosistema: Registro degli Utenti
class UserRegistry {
    private $users = [];

    public function register(User $user) {
        $this->users[] = $user;
    }

    public function findByName($name) {
        foreach ($this->users as $user) {
            if ($user->getName() == $name) {
                return $user;
            }
        }
        return null;
    }
}

// Sottosistema: Biglietteria
class TicketOffice {
    public function issueTicket(Movie $movie, $seatNumber) {
        return new Ticket($movie, $seatNumber);
    }
}

// Facade: Sistema di Cinema
class CinemaFacade {
    private $catalog;
    private $registry;
    private $ticketOffice;

    public function __construct() {
        $this->catalog = new MovieCatalog();
        $this->registry = new UserRegistry();
        $this->ticketOffice = new TicketOffice();
    }

    public function addMovie($title, $duration) {
        $this->catalog->add(new Movie($title, $duration));
    }

    public function addUser($name) {
        $this->registry->register(new User($name));
    }

    public function bookTicket($userName, $movieTitle, $seatNumber) {
        // Coordina i sottosistemi: cerca l'utente e il film
        $user = $this->registry->findByName($userName);
        $movie = $this->catalog->findByTitle($movieTitle);

        // Se l'utente e il film esistono, la biglietteria emette il biglietto
        if ($user && $movie) {
            $ticket = $this->ticketOffice->issueTicket($movie, $seatNumber);
            return $ticket->getDetails();
        } else {
            return "Prenotazione fallita: utente o film non trovati.";
        }
    }
}

// Utilizzo della Facade
$cinema = new CinemaFacade();
$cinema->addMovie("Inception", 148);
$cinema->addMovie("The Matrix", 136);
$cinema->addUser("Alice");
$cinema->addUser("Bob");

// Prenotazione di un biglietto
echo $cinema->bookTicket("Alice", "Inception", "A1") . "\n";  
// Output: Biglietto per il film 'Inception' al posto A1.

echo $cinema->bookTicket("Bob", "The Matrix", "B2") . "\n";  
// Output: Biglietto per il film 'The Matrix' al posto B2.

echo $cinema->bookTicket("Charlie", "Inception", "C3") . "\n";  
// Output: Prenotazione fallita: utente o film non trovati.

Spiegazione

  • MovieCatalog, UserRegistry e TicketOffice sono i sottosistemi: ognuno contiene i propri dati e la propria logica (film, utenti, emissione dei biglietti).
  • CinemaFacade non gestisce dati propri: in bookTicket() si limita a coordinare i sottosistemi, cercando l’utente e il film e chiedendo alla biglietteria di emettere il biglietto.
  • Il codice client usa solo la facciata e non deve conoscere le classi dei sottosistemi né l’ordine in cui vanno chiamate.

TORNA ALLA GUIDA

Copiato