Patrones Creacionales en PHP

Guía Completa de los Patrones Creacionales en PHP

Los patrones de diseño son soluciones generales para problemas comunes en el desarrollo de software. Ayudan a crear sistemas flexibles y reutilizables al proporcionar métodos ya probados para resolver problemas de diseño.

Los patrones creacionales son patrones de diseño que se enfocan en la creación de objetos. Abstraen el proceso de instanciación y ayudan a hacer un sistema independiente de cómo se crean, componen y representan sus objetos.

Entendiendo estos patrones podremos crear sistemas PHP más flexibles, escalables y de fácil mantenimiento.

Introducción a los Patrones Creacionales

Los patrones creacionales resuelven problemas recurrentes relacionados con la creación de objetos. Nos ayudan a encapsular y abstraer dicho proceso de creación.

Los objetivos principales de los patrones creacionales son:

  • - Crear objetos de una manera que sea independiente de la lógica del sistema.

  • - Ocultar la lógica de creación y los detalles de implementación de los objetos creados.

  • - Permitir agregar nuevas clases sin modificar el código cliente existente.

  • - Crear objetos complejos a partir de otros más simples de forma incremental.

Algunas situaciones donde aplican bien los patrones creacionales:

  • - Cuando se requiere una instanciación compleja de clases que no debe estar expuesta al código cliente.

  • - Cuando se necesita trabajar con diferentes implementaciones de una interfaz común.

  • - Cuando las clases deben ser creadas de forma dinámica y configurable.

  • - Cuando se requiere reutilizar objeto similares de forma eficiente.

Veamos ahora algunos de los patrones creacionales más utilizados en el desarrollo PHP.


Patrón Singleton en PHP

El patrón Singleton garantiza que una clase solo tenga una instancia y proporciona un punto de acceso global a ella. Es utilizado cuando se necesita exactamente una instancia de una clase para coordinar acciones en todo el sistema.

Estructura Del Patrón Singleton

  • 1º Singleton (clase)

    • - attributes (propiedades de la instancia única)

    • - methods

  • 2º Client (código cliente)

Implementación Del Patrón Singleton

Para implementar Singleton en PHP se restringe la creación de instancias de la clase mediante el constructor privado. Luego se proporciona un método estático para acceder a la instancia única (Estructura Punto 1º).

<?php
class Singleton {

  private static $instance;

  private function __construct() {
    // Inicialización
  }

  public static function getInstance() {
    if (!self::$instance) {
      self::$instance = new self();
    }
    return self::$instance;
  }

}

El código cliente(Estructura Punto 2º) obtiene la instancia única a través del método estático getInstance():

<?php

$singleton = Singleton::getInstance();

Ventajas Patrón Singleton:

  • - Garantiza que una clase solo tenga una instancia.

  • - Proporciona un punto de acceso global a la instancia.

  • - Permite controlar las referencias y reducir el uso de memoria.

Desventajas Patrón Singleton:

  • - Viola el principio de responsabilidad única. La clase gestiona su propia unicidad.

  • - Puede ocultar un mal diseño.

  • - Dificulta realizar tests unitarios.

  • - Rompe el patrón de clases base de PHP.

El patrón Singleton debe usarse con precaución ya que introduce acoplamiento y estado global en el sistema. Debe preferirse la inyección de dependencias siempre que sea posible.


Patrón Factory Method en PHP

El patrón Factory Method define una interfaz para crear objetos, pero deja a las subclases decidir qué clase instanciar. Permite crear objetos de forma configurable.

Estructura Del Patrón Factory Method

  • 1º Product (Interface o Clase)

  • 2º ConcreteProduct (Clases concretas que implementan el producto)

  • 3º Creator (Declara el método fábrica)

  • 4º ConcreteCreator (Redefine el método fábrica para crear un producto concreto)

  • 5º Client

Implementación Del Patrón Factory Method

Se crea una interfaz genérica para el producto(Estructura Punto 1º) y varias clases que la implementan(Estructura Punto 2º):

<?php

interface PaymentMethod {
  public function pay();
}

class PayPal implements PaymentMethod {
  public function pay() {
    // Código de pago PayPal
  }
}

class CreditCard implements PaymentMethod {
  public function pay() {
    // Código de pago tarjeta de crédito
  }
}

Luego se declara el método fábrica(Estructura Punto 3º) en la clase creadora:

<?php

abstract class Payment {

  protected abstract function getMethod();

  public function pay() {
    $method = $this->getMethod();
    $method->pay();
  }

}

Finalmente las subclases concretas(Estructura Punto 4º) definen la implementación del método fábrica:

<?php

class PayPalPayment extends Payment {

  protected function getMethod() {
    return new PayPal();
  }

}

class CreditCardPayment extends Payment {

  protected function getMethod() {
    return new CreditCard();
  }

}

Y se utiliza así(Estructura Punto 5º):

<?php

$paypal = new PayPalPayment();
$paypal->pay(); // Usa PayPal

$creditcard = new CreditCardPayment();
$creditcard->pay(); // Usa tarjeta de crédito

Ventajas Patrón Factory Method:

  • - Oculta los detalles de implementación de las clases creadas.

  • - Centraliza el código de instanciación en un solo punto.

  • - Sigue el principio de responsabilidad única.

Desventajas Patrón Factory Method:

  • - La lógica de creación se dispersa en subclases.

  • - Puede resultar complejo mantener un alto número de creadores.

El patrón Factory Method es muy útil cuando se necesita crear objetos de diferentes tipos siguiendo una interfaz común. Proporciona un alto grado de flexibilidad y desacoplamiento en la creación de objetos.


Patrón Abstract Factory en PHP

El patrón Abstract Factory proporciona una interfaz para crear familias de objetos relacionados sin necesidad de especificar sus clases concretas.

Estructura Del Patrón Abstract Factory

  • 1º AbstractFactory (Interface)

  • 2º ConcreteFactory (Implementaciones)

  • 3º AbstractProduct (Interface de producto)

  • 4º ConcreteProduct (Implementaciones)

  • 5º Client

Implementación Del Patrón Abstract Factory

Se define una interfaz de fábrica abstracta(Estructura Punto 1º) y varias implementaciones concretas(Estructura Punto 2º):

<?php

interface GUIFactory {
  public function createButton();
  public function createCheckbox();
}

class WinFactory implements GUIFactory {
  public function createButton() {
    return new WinButton();
  }

  public function createCheckbox() {
    return new WinCheckbox();
  }
}

class MacFactory implements GUIFactory {
  public function createButton() {
    return new MacButton();
  }

  public function createCheckbox() {
    return new MacCheckbox();
  }
}

Luego se crean las interfaces(Estructura Punto 3º) e implementaciones(Estructura Punto 4º) de los productos:

<?php

interface Button {
  public function paint();
}

class WinButton implements Button {
  public function paint() {
    // Pintar botón Windows
  }
}

class MacButton implements Button {
  public function paint() {
    // Pintar botón Mac
  }
}

// Lo mismo para Checkbox

Y se utiliza así(Estructura Punto 5º):

<?php

$gui = new WinFactory();
$button = $gui->createButton();
$checkbox = $gui->createCheckbox();

Ventajas Patrón Factory Method:

  • - Aísla la creación de objetos complejos.

  • - Facilita intercambiar familias de productos.

  • - Evita acoplamiento fuerte entre clases.

  • - Centraliza la creación de objetos en un punto.

Desventajas Patrón Factory Method:

  • - La introducción de nuevos productos es compleja.

  • - Puede resultar overkill para requisitos simples.

Este patrón resulta muy útil cuando existen familias de objetos relacionados que se utilizan conjuntamente. Permite configurar el sistema para utilizar una u otra familia de productos.


Patrón Builder en PHP

El patrón Builder desacopla la construcción de un objeto complejo de su representación. Permite crear distintas representaciones usando el mismo código de construcción.

Estructura Del Patrón Builder

  • 1º Builder (Interface)

  • 2º ConcreteBuilder (Implementaciones)

  • 3º Director (Ordena los pasos de construcción)

  • 4º Product (Objeto complejo)

Implementación Del Patrón Builder

Primero se define una interfaz de builder(Estructura Punto 1º) con los métodos para la construcción(Estructura Punto 2º):

<?php

interface Builder {
  public function buildPartA();
  public function buildPartB();
  public function buildPartC();
  public function getResult();
}

Luego se implementan builders concretos:

<?php

class TextBuilder implements Builder {
  private $result;

  public function buildPartA() {
    $this->result .= "Texto A \\n";
  }

  public function buildPartB() {
    $this->result .= "Texto B \\n";
  }

  public function buildPartC() {
    $this->result .= "Texto C \\n";
  }

  public function getResult() {
    return $this->result;
  }
}

class HTMLBuilder implements Builder {
  // Implementación similar pero genera HTML
}

El director(Estructura Punto 3º) ordena el proceso:

<?php

class Director {

  private $builder;

  public function construct(Builder $builder) {
    $this->builder = $builder;

    $this->builder->buildPartA();
    $this->builder->buildPartB();
    $this->builder->buildPartC();
  }

}

Y se utiliza de la siguiente manera(Estructura Punto 4º):

<?php

$textBuilder = new TextBuilder();
$director = new Director($textBuilder);
$director->construct();

echo $textBuilder->getResult();

// Obtiene texto

$htmlBuilder = new HTMLBuilder();
$director->construct($htmlBuilder);

echo $htmlBuilder->getResult();

// Obtiene HTML

Ventajas Patrón Builder:

  • - Permite crear objetos complejos paso a paso.

  • - Desacopla la representación de un objeto de su construcción.

  • - Permite reutilizar el mismo código de construcción para distintas representaciones.

  • - Oculta los detalles de implementación de los objetos creados.

Desventajas Patrón Builder:

  • - Requiere crear una interfaz y clases de builder separadas.

  • - La lógica de construcción se dispersa en varias clases y métodos.

Este patrón resulta útil para crear objetos complejos de forma independiente< a como serán representados finalmente. También permite reutilizar el código de construcción eficientemente.


Conclusión

Los patrones creacionales resuelven de manera elegante problemas comunes en la creación de objetos en PHP. Nos ayudan a desacoplar el sistema de cómo se crean e instancian las clases.

Cada patrón tiene diferentes pros, contras y casos de uso. Conviene conocerlos para poder elegir el más adecuado según el contexto y requerimiento específico.

Algunas recomendaciones finales al usar patrones creacionales:

  • - No forzar su aplicación si no resuelven un problema concreto. Pueden agregar complejidad innecesaria.

  • - Preferir la inyección de dependencias y la inversión de control cuando sea posible.

  • - No utilizar Singleton como reemplazo de variables globales.

  • - No abusar de Abstract Factory, aplicarlo solo cuando se necesiten familias de objetos.

  • - Usar Factory Method cuando se requieran tipos específicos configurables.

  • - Aplicar Builder para construcciones complejas independientes de la representación.

Los patrones de diseño bien implementados nos permiten crear sistemas PHP más flexibles, escalables y de fácil mantenimiento. ¡Los patrones creacionales son una pieza clave de esto!


Ejercicios Resueltos

  • Ejercicio 1

    Implementar una clase Logger que permita ir registrando eventos en un archivo log.txt y que solo pueda existir una instancia de la clase (patrón Singleton).

    <?php
    
    class Logger {
    
      private static $instance;
      private $filepath;
    
      private function __construct() {
        $this->filepath = '/tmp/log.txt';
      }
    
      public static function getInstance() {
        if (!self::$instance) {
          self::$instance = new self();
        }
        return self::$instance;
      }
    
      public function log($message) {
        file_put_contents($this->filepath, $message . PHP_EOL, FILE_APPEND);
      }
    
    }
    
    // Uso
    
    $logger = Logger::getInstance();
    $logger->log("Mensaje 1");
  • Ejercicio 2

    Implementar una fábrica de vehículos que permita crear autos, motos y camiones (patrón Factory Method).

    <?php
    
    interface Vehicle {
      public function drive();
    }
    
    class Car implements Vehicle {
      public function drive() {
        echo "Conduciendo auto";
      }
    }
    
    class Truck implements Vehicle {
      public function drive() {
        echo "Conduciendo camión";
      }
    }
    
    abstract class VehicleFactory {
    
      abstract public function createVehicle();
    
      public function startDelivery() {
        $vehicle = $this->createVehicle();
        $vehicle->drive();
      }
    
    }
    
    class CarFactory extends VehicleFactory {
    
      public function createVehicle() {
        return new Car();
      }
    
    }
    
    class TruckFactory extends VehicleFactory {
    
      public function createVehicle() {
        return new Truck();
      }
    
    }
    
    $carFactory = new CarFactory();
    $carFactory->startDelivery(); // Conduciendo auto
    
    $truckFactory = new TruckFactory();
    $truckFactory->startDelivery(); // Conduciendo camión
  • Ejercicio 3

    Implementar un builder para generar archivos PDF y DOCX a partir de una estructura de datos común (patrón Builder).

    <?php
    
    interface DocumentBuilder {
      public function buildHeader();
      public function buildContent();
      public function buildFooter();
      public function getDocument();
    }
    
    class PDFBuilder implements DocumentBuilder {
      private $pdf;
    
      public function buildHeader() {
        $this->pdf->setHeader("PDF Header");
      }
    
      public function buildContent() {
        $this->pdf->addPage("PDF Content");
      }
    
      public function buildFooter() {
        $this->pdf->setFooter("PDF Footer");
      }
    
      public function getDocument() {
        return $this->pdf;
      }
    }
    
    class DOCXBuilder implements DocumentBuilder {
      // Implementación similar para DOCX
    }
    
    // Código para usar los builders
    
    $data = ["header" => "Document Title", "content" => [...], "footer" => "Copyright"];
    
    $pdfBuilder = new PDFBuilder();
    $docxBuilder = new DOCXBuilder();
    
    buildDocument($data, $pdfBuilder);
    $pdf = $pdfBuilder->getDocument();
    
    buildDocument($data, $docxBuilder);
    $docx = $docxBuilder->getDocument();
    
    function buildDocument($data, $builder) {
      $builder->buildHeader($data["header"]);
      $builder->buildContent($data["content"]);
      $builder->buildFooter($data["footer"]);
    }
    

Preguntas Frecuentes

Los patrones creacionales son patrones de diseño que resuelven problemas comunes relacionados con la creación de objetos. Nos ayudan a encapsular y abstraer dicho proceso de creación.

El patrón Singleton se aplica cuando se necesita restringir la creación de una clase a una única instancia. Es útil para representar recursos únicos en el sistema que deben ser globalmente accesibles.

Factory Method crea objetos de distintas variantes de un tipo, mientras que Abstract Factory crea familias de objetos relacionados. Factory Method es más simple de implementar que Abstract Factory.

El patrón Builder permite construir objetos complejos paso a paso y desacoplar dicha construcción de la representación final del objeto. Es útil para crear distintas representaciones de un mismo objeto complejo.

Deja un Comentario

¡Bienvenido a nuestro sitio web!

Este sitio utiliza cookies para mejorar tu experiencia de navegación y proporcionar funciones adicionales relacionadas con el análisis de tráfico y el rendimiento del sitio. Política de cookies.