Patrones de diseño en PHP. Patrón Factory Method


Patrones de diseño en PHP. Patrón Factory Method

Continuamos con el siguiente patrón, Abstract Method, que pertenece a los patrones de creación. Actualizamos el ejemplo del catalogo visto en el articulo anterior.



En el articulo anterior implementamos un catalogo aplicando el patrón Abstract Factory pero agregar un nuevo producto (libro) requería cambiar la clase AbstractBookFactory y todas las clases que dependían de esta.

Propósito

Programar una interfaz (o clase abstracta) que defina un método para crear los objetos pero que deje a las subclases decidir que objeto instanciar.

Sinónimos

Conocido también como Virtual Constructor.

Motivación

Diagrama de nuestro ejemplo con el Patrón Factory Method
Diagrama de nuestro ejemplo con el Patrón Factory Method
El Factory Method consiste en crear objetos como método de plantilla para implementar un algoritmo. Una clase abstracta especifica todo el comportamiento estándar y genérico (utilizando "marcadores de posición" virtuales puros para los pasos de creación), y luego delega los detalles de creación a las subclases que proporciona el cliente.


Aplicabilidad

Usar el patrón Factory Method cuando
  • Una clase no puede anticipar la clase de objetos que debe crear.
  • Una clase quiere que sus subclases especifiquen los objetos que crea.
  • Las clases delegan la responsabilidad en una de varias subclases auxiliares.

Participantes

Estructura general del Patrón Factory Method
Estructura general del Patrón Factory Method
  • AbstractBookFactory. Define un método para crear objetos.
  • OReillyFactoryMethod. Implementa el método y retorna los objetos.
  • AbstractBook y AbstractProductA. Definen métodos propios de un libro.
  • ProductA. Es la clase que crea los objetos.



Colaboraciones

La clase AbstractBookFactory confía en sus subclases la implementación del método que crea los objetos.

Consecuencias

La clase AbstractBookFactory no es vinculada con ninguna clase en especifico, esto es tarea de sus subclases.
La creación de objetos dentro de una clase con Factory Method siempre sera más flexible que crear objetos directamente dentro de esta.
Conectar jerarquías de clases paralelas. En nuestro ejemplo usamos al cliente (Catalogo) para que nos retorne una serie de libros que pedimos según sus editoriales por medio de las clases OReillyBookFactoryMethod y SamsBookFactoryMethod pero se podría usar directamente la clase OReillyMySQLBook para ubicar libros de la editorial OReilly y temática MySQL, lo que seria útil en un buscador.

Implementación

Se pueden encontrar los siguientes problemas en este patrón:
Cuando la clase OReillyBookFactoryMethod es una clase abstracta y no proporciona una implementación para el método de fábrica que declara y requiere subclases para definir una implementación, porque no hay un incumplimiento razonable. Resuelve el dilema de tener que crear instancias de clases imprevisibles.
Cuando la clase OReillyBookFactoryMethod es una clase concreta y proporciona una implementación predeterminada para el método de fábrica. También es posible tener una clase abstracta que defina una implementación predeterminada, pero esto es menos común. Aun así nos otorga principalmente flexibilidad. Sigue una regla que dice: "Crea objetos en una operación separada para que las subclases puedan anular la forma en que se crearon". Esta regla asegura que los diseñadores de subclases puedan cambiar la clase de objetos que su clase padre crea en caso de necesidad.
La creación de múltiples tipos de productos. Como en nuestro ejemplo podemos crear libros según su editorial y ampliar la cantidad de estas según las necesidades del cliente (Catalogo). La clase OReillyBookFactoryMethod implementa el método makeBook() definido por AbstractBookFactory que recibe un parámetro, el cual le permite decidir que objeto crear.

Código de Ejemplo

La clase AbstractBookFactory
/* Clase AbstractFactoryMethod */
namespace Blockpc\Patrones\FactoryMethod;
abstract class AbstractFactoryMethod {
abstract public function makeBook($editor);
}
Nuestra clase OReillyBookFactoryMethod quedaría
/* Clase OReillyBookFactoryMethod */
namespace Blockpc\Patrones\FactoryMethod\OReilly;
use Blockpc\Patrones\FactoryMethod\AbstractFactoryMethod;
final class OReillyBookFactoryMethod extends AbstractFactoryMethod {
private $editorial = "OReilly";
public function makeBook($tematica) {
$libro = NULL;
switch ($tematica) {
case "php":
$libro = new OReillyPHPBook;
break;
case "mysql":
$libro = new OReillyMySQLBook;
break;
default:
$libro = new OReillyPHPBook;
break;
}
return $libro;
}
}
Nuestra clase SamsBookFactoryMethod quedaría
/* Clase SamsBookFactoryMethod */
namespace Blockpc\Patrones\FactoryMethod\Sams;
use Blockpc\Patrones\FactoryMethod\AbstractFactoryMethod;
final class SamsBookFactoryMethod extends AbstractFactoryMethod {
private $editorial = "Sams";
public function makeBook($tematica) {
$libro = NULL;
switch ($tematica) {
case "php":
$libro = new SamsPHPBook;
break;
case "mysql":
$libro = new SamsMySQLBook;
break;
default:
$libro = new SamsPHPBook;
break;
}
return $libro;
}
}
En la clase Catalogo realizamos el cambio en el método principal.
/*  Clase Catalogo */
public function pruebaPatronFactoryMethod($bookFactoryInstance) {
$phpLibro = $bookFactoryInstance->makeBook('php');
$this->escribir('Primer Libro PHP Autor: '.$phpLibro->getAuthor());
$this->escribir('Primer Libro PHP Titulo: '.$phpLibro->getTitle());
$mySqlLibro = $bookFactoryInstance->makeBook('mysql');
$this->escribir('MySQL Autor: '.$mySqlLibro->getAuthor());
$this->escribir('MySQL Titulo: '.$mySqlLibro->getTitle())
$this->escribir('');
}


Usos Conocidos

EL patrón Factory Method lo encontramos mayoritariamente en frameworks y en algunas librerías de diseño.

Patrones Relacionados

Este patrón se relaciona con Abstract Factory, Prototypes y Template Methd

Ultimas Consideraciones

Este patrón se puede aplicar fácilmente cuando las clases concretas (nuestras clases referentes a temáticas y editoriales en el ejemplo) sean fijas. Agregar una nueva temática o editorial no es complicado pero si se debe hacer muchas veces, la implementación del método makeBook() se podría complicar.

El código fuente lo puedes descargar desde acá.

Saludos y hasta el próximo articulo.

Etiquetas patrones diseño solid

Ultima actualización Miércoles 18 de Julio, 2018




Agregar Comentario