Patrones de diseño en PHP. Patrón Prototype


Patrones de diseño en PHP. Patrón Prototype

Tercer articulo sobre patrones de diseño. Revisamos el patrón Prototype que viene siendo parte de los patrones creacionales.



El concepto de este patrón es simple: en lugar de crear un objeto, se clona, es decir, se realiza una copia exacta de otro objeto dado, denominado prototipo. Afortunadamente PHP trae el método mágico __clone() lo que permite que implementar este patrón sea mas sencillo. En otros lenguajes se necesita construir esta función.
En PHP la clonación de un objeto requiere solo dos lineas

/* Clase Objeto */
class Objeto {
public function __construct() {
echo "Soy el constructor<br>";
}
public function __clone() {
echo "Soy el clon<br>";
}
}
/* Clonando un objeto */
$objeto = new Objeto();
$clon = clone $objeto;
Algo a tener en cuenta es que durante la creación de un objeto se llama internamente al método __construct() de la clase, un objeto clonado no hace uso de esta llamada por lo que se ahorran recursos del sistema y lo que ademas nos indica que los constructores no deberían incluir (de ser posible) lógica de programación que sea diferente de la de establecer variables.

Propósito

La idea es que los objetos se vayan creando por copia de un objeto prototipo creado.

Sinónimos

Sin sinónimos conocidos.

Motivación

Este patrón proporciona una conveniente forma de copiar objetos ya creados y con ello acceder a variables privadas que de otra forma no se podría.

Aplicabilidad

Diagrama estructural de nuestro ejemplo
Diagrama estructural de nuestro ejemplo
  • Use el patrón Prototipo cuando un sistema debe ser independiente de cómo los productos son creados.
  • Cuando las clases para crear instancias se especifican en tiempo de ejecución.
  • Para evitar construir una jerarquía de clases de fábricas que sea paralela a la jerarquía de clases de productos.
  • Cuando las instancias de una clase pueden tener pocas combinaciones diferentes de estado.

En el tercer punto hacemos referencia a la jerarquías de editoriales y de temáticas. En el cuarto punto, y estudiando el ejemplo, es obvio que los estados son pocos (cuatro) y van en pares (editorial-temática), estos son (OReilly-PHP), (OReilly-MySQL), (Sams-PHP), (Sams-MySQL).

Participantes

Diagrama estructural del Patrón Prototype
Diagrama estructural del Patrón Prototype
  • Prototype. Que serian las clases abstractas o bien interfaces (coloradas en amarillo).
  • ConcreteProduct. Representan las clases instanciables y clonables (coloreadas en verde).
  • Client. Nuestro Catalogo de siempre, es quien muestra los libros de las editoriales
Se debe recordar que un objeto primero debe ser creado para que pueda ser clonado.


Consecuencias

Principalmente oculta las clases de productos concretos al cliente (editoriales o temáticas), reduciendo así la cantidad de nombres que los clientes conocen. A nuestro catalogo se le pide un objeto AbstractPrototype y son sus subclases quienes devuelven los libros pedidos.
Todo lo anterior permite configurar una aplicación con clases dinámicas, registrando un objeto y pasando copias de este al cliente cuando pida, por ejemplo en un carro de compra.

Implementación

En nuestro ejemplo sabemos que tanto los objetos editoriales como temáticas son jerarquías independientes y no son fijas (a futuro podríamos agregar otras editoriales o temáticas). Se podría implementar un administrador de editoriales que lleve un registro asociativo de estos y así el catalogo recurrir a este. Ídem para las temáticas.
Se podría aprovechar el método __clone() para agregar información al objeto clonado.

Código de Ejemplo

A nuestras clases abstractas se les agrega el método abstracto __clone() que si bien no es necesario debido a que en PHP este método es parte del lenguaje, el patrón prototype lo exige. Así la Clase AbstractBook quedaría:
/* Clase AbstractBook */
namespace Blockpc\Patrones\Prototype;
abstract class AbstractBook {
abstract public function getAuthor();
abstract public function getTitle();
public function getTematica() {
return $this->tematica;
}
}
La Clase AbstractMySQLBook quedaría:
/* Clase AbstractMySQLBook */
namespace Blockpc\Patrones\Prototype;
abstract class AbstractMySQLBook extends AbstractBook {
protected $tematica = "MySQL";
abstract function __clone();
}
La Clase AbstractPHPBook quedaría:
/* Clase AbstractPHPBook */
namespace Blockpc\Patrones\Prototype;
abstract class AbstractPHPBook extends AbstractBook {
protected $tematica = "PHP";
abstract function __clone();
}
La Clase AbstractPrototype quedaría:
/* Clase AbstractPrototype */
namespace Blockpc\Patrones\Prototype;
abstract class AbstractPrototype {
abstract public function makeBook($editor);
abstract public function __clone();
public function getEditorial() {
return $this->editorial;
}
}
El resto de las clases concretas que extiendan de estas deben implementar el método __clone().
El código fuente ira al final del articulo como siempre.

Usos Conocidos

En nuestro ejemplo tenemos la clase AbstractPrototype que seria el prototipo de todas las editoriales que tengamos (por ahora OReilly y Sams) y seran estas ultimas las clonadas. Igual caso con las temáticas (por ahora PHP y MySQL).
Evitar el costo inherente a la creación de un nuevo objeto en la forma estándar.

Patrones Relacionados

Este patrón se hace fuerte junto a los patrones Composite y Decorator

Ultimas Consideraciones

Acá cabe recordar que la implementación del ejemplo se a venido desarrollando hace dos artículos y empezamos con el patrón Abstract Factory y como siempre he dicho, la idea es conocer con un único ejemplo la mayoría de los patrones y poder entender las diferencias entre ellos.
El siguiente a revisar sera el patrón Builder en el cual veremos un buen cambio en nuestras clases abstractas.
El código fuente lo puedes descargar desde acá.
Saludos y hasta el próximo articulo.

Etiquetas patrones diseño solid

Ultima actualización Jueves 09 de Agosto, 2018




Agregar Comentario