Patrones de Diseño en PHP

23:07 manu 0 Comments

Un patrón de diseño es una estructura general que puede ser usada para solucionar un problema. No se trata ni de una librería ni de un esqueleto. Para que una solución se considere un patrón de diseño debe ser efectiva y reutilizable, es decir, que pueda aplicarse y resolver problemas similares.

Existen 3 grandes grupos de patrones de diseño: Patrones Creacionales, Patrones Estructurales y Patrones de Comportamiento.

Patrones Creacionales

Estos patrones están enfocados al proceso de creación de instancias, en particular, de ocultar el proceso de creación y de encapsular.Existen 5 tipos de patrones Creacionales:

  • - Abstract Factory
  • - Builder
  • - Factory Method
  • - Prototype
  • - Singleton

Voy a analizar los más relevantes, suficiente para poder entender este tipo de patrones:

1. Factory

Es uno de los más utilizados. En este patrón una clase intermedia (Factory) se encarga de crea el objeto que quieres utilizar.

class Coche
{
    private $marca;
    private $modelo;

    public function __construct($marca, $modelo)
    {
        $this->marca = $marca;
        $this->modelo = $modelp;
    }

    public function getMarcaYModelo()
    {
        return $this->marca . ' ' . $this->modelo;
    }
}

class CocheFactory
{
    public static function create($marca, $modelo)
    {
        return new Coche($marca, $modelo);
    }
}

$ibiza = CocheFactory::create('Seat', 'Ibiza');

Como podéis ver, en este código se utiliza un Factory para crear el objeto Coche. La gran ventaja de hacerlo a través de un Factory y no directamente es que en el caso de que tengas que modificar algo de la clase Coche, tan sólo tendrías que actualizar el Factory, y no las mil referencias que puedas tener en tu código. Este patrón consigue un acoplamiento muy bajo (interdependencia entre objetos).

¿Cuándo utilizar este patron? Si una clase tiene un número finito y conocido de objetos que debe crear, como por ejemplo una aplicación de el mundo, con distintos objetos para los continentes (finitos y conocidos) no sería aconsejado. En cambio, si la aplicación es sobre insectos del mundo, ya sabes de antemano que nuevas especies van a ser descubiertas, por tanto este patrón se ajustaría perfectamente.

2. Singleton

Cuando diseñamos aplicaciones web en muchas ocasiones interesa tener una sola instancia de una determinada clase. Un ejemplo claro serían objetos globales (como una clase con configuración), o un recurso compartido (como una "Cola de eventos").

En muchos casos se recomienda la inyección de dependencia (patrón en el que se suministran objetos a una clase en lugar de ser la propia clase quien cree el objeto) en lugar del patrón Singleton. Si estás pensando que el patrón de inyección de dependencia suena igual que el patrón Factory, es porque la diferencia entre ellas es bastante difusa.

La inyección de dependencia significa proporcionar los objetos que un objeto necesita (sus dependencias) via constructor, setters, o incluso mediante el framework que utilices, en lugar de hacer que los construya él mismo.

class Singleton
{
    private static $instance;
    
    public static function getInstance()
    {
        if (null === static::$instance) {
            static::$instance = new static();
        }        
        return static::$instance;
    }

    /**
     * Constructor para evitar la creación de una nueva instancia
     * a través del operador "new" desde fuera de esta clase
     */
    protected function __construct()
    {
    }

    /**
     * Método para prevenir la clonación de la instancia
     *
     * @return void
     */
    private function __clone()
    {
    }

    /**
     * Método para prevenir la deserialización de la instancia
     *
     * @return void
     */
    private function __wakeup()
    {
    }
}
$obj = Singleton::getInstance();

Patrones Estructurales

Estos patrones examinan como se componen los objetos y las clases. Usan herencia para crear interfaces. Entre ellos encontramos:

  • - Adapter (class y object)
  • - Bridge
  • - Composite
  • - Decorator
  • - Façade
  • - Flyweight
  • - Proxy

1. Composite

El patron Composite consiste en agrupar y gestionar grupos de objetos similares, de forma que su tratamiento no se distinga al de un objeto. Es un patrón sencillo pero puede llegar a confundir. Sirve para construir objetos complejos a partir de otros más simples y similares entre sí, gracias a la composición recursiva y a una estructura en forma de árbol

Un ejemplo claro es una lista de TO-DOs, cada elemento de la lista es una tarea, pero puede contener otras subtareas y así sucesivamente.


2. Decorator

Partamos de la base que tenemos un clase que no podemos modificar pero necesitamos introducir una nueva funcionalidad. El patrón Decorator propone crear una nueva clase que implemente esta interfaz envolviendo a la clase principal. Podemos tener varios clases Decorator para una misma clase, por lo que el diagrama nos quedaría así:


Donde ConcreteComponent es la clase principal que queremos modificar, la clase Decorator representa a todos los posibles Decorators, y finalmente Component es el resultado final.

class Book {
    private $author;
    private $title;
    function __construct($title_in, $author_in) {
        $this->author = $author_in;
        $this->title  = $title_in;
    }
    function getAuthor() {
        return $this->author;
    }
    function getTitle() {
        return $this->title;
    }
    function getAuthorAndTitle() {
      return $this->getTitle().' by '.$this->getAuthor();
    }
}

class BookTitleDecorator {
    protected $book;
    protected $title;
    public function __construct(Book $book_in) {
        $this->book = $book_in;
        $this->resetTitle();
    }   
    //doing this so original object is not altered
    function resetTitle() {
        $this->title = $this->book->getTitle();
    }
    function showTitle() {
        return $this->title;
    }
}

class BookTitleExclaimDecorator extends BookTitleDecorator {
    private $btd;
    public function __construct(BookTitleDecorator $btd_in) {
        $this->btd = $btd_in;
    }
    function exclaimTitle() {
        $this->btd->title = "!" . $this->btd->title . "!";
    }
}

class BookTitleStarDecorator extends BookTitleDecorator {
    private $btd;
    public function __construct(BookTitleDecorator $btd_in) {
        $this->btd = $btd_in;
    }
    function starTitle() {
        $this->btd->title = Str_replace(" ","*",$this->btd->title);
    }
}

$patternBook = new Book('Gamma, Helm, Johnson, and Vlissides', 'Design Patterns');
 
$decorator = new BookTitleDecorator($patternBook);
$starDecorator = new BookTitleStarDecorator($decorator);

Patrones de Comportamiento

Los patrones de comportamiento tratan sobre la comunicación entre objetos. Compuesto por los siguientes patrones:

  • - Chain of responsibility
  • - Command
  • - Interpreter
  • - Iterator
  • - Mediator
  • - Memento
  • - Null Object
  • - Observer
  • - State
  • - Strategy
  • - Template method
  • - Visitor

1. Strategy

Consiste en encapsular familias de algoritmos permitiendo a la clase responsable de instanciar un algoritmo especifico no necesitar tener conocimiento de la actual implementación.

Definir una familia de algoritmos, encapsula cada uno de ellos y los hace intercambiables. Es una estrategia que permite que al algoritmo variar dependiendo del uso que los clientes necesiten. Esa abstracción viene mediante una interfaz, y oculta la implementación de las clases derivadas.

interface OutputInterface{
    public function load();
}

class SerializedArrayOutput implements OutputInterface{
    public function load()
    {
        return serialize($arrayOfData);
    }
}

class JsonStringOutput implements OutputInterface{
    public function load()
    {
        return json_encode($arrayOfData);
    }
}

class ArrayOutput implements OutputInterface{
    public function load()
    {
        return $arrayOfData;
    }
}

class SomeClient{
    private $output;

    public function setOutput(OutputInterface $outputType)
    {
        $this->output = $outputType;
    }

    public function loadOutput()
    {
        return $this->output->load();
    }
}

$client = new SomeClient();

// Quieres un array?
$client->setOutput(new ArrayOutput());
$data = $client->loadOutput();

// Quieres un JSON?
$client->setOutput(new JsonStringOutput());
$data = $client->loadOutput();

Como acabas de ver existen muchísimos patrones de diseño, de hecho no deja de aparecer cada cierto tiempo alguno nuevo. Por eso vamos a terminar mencionando un par que no aparecen en la base de patrones de diseño, pero actualmente de los más usados en el mundo web.

1. Patrón Front Controller

Esté patrón es muy común en el mundo web ya que especifica una única entrada a una web (por ejemplo index.php) que se encarga de atender todas las peticiones. Este código es el responsable de cargar todas las dependencias y de procesar todas las peticiones, así como de generar las correspondientes respuestas.

2. Patrón Modelo-Controlador-Vista o MVC

Permite descomponer el código en tres objetos lógicos. El modelo es el encargado de acceder a la capa de datos (generalmente la base de datos). Los controladores gestionan las peticiones y procesan los datos del Modelo que cargan en las Vistas. Las Vistas son plantillas HTML que se devuelve al cliente.

0 comentarios: