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


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

En este primer articulo revisaremos el patrón de diseño Abstract Factory, perteneciente a la categoría de patrones de creación.



Vamos a suponer que queremos implementar un catalogo de los libros impresos que tenemos en la biblioteca de nuestra casa o de los libros digitales en nuestro computador o incluso la de algún colegio.
El catalogo estará dividido por temática (tenemos libros de PHP y de MySQL) y por editorial (OReilly y Sams).
De cada libro necesitamos la información del titulo y su autor.

Propósito del Patrón

Sirve para crear series de objetos relacionados o dependientes sin especificar sus clases concretas.
Por lo general, todas las clases creadas implementan la misma interfaz (o extienden de la misma clase abstracta).
Al cliente de la fábrica abstracta no le importa cómo se crean estos objetos, simplemente sabe que debe usarla.

Sinónimos

También conocido como Kit

Motivación

Según el supuesto debemos implementar un catalogo (cliente) pero si lo hacemos con los libros (productos) de nuestro computador de una manera, lo mas seguro es que no podamos reutilizar esa catalogo para un colegio. Así, para estandarizar el catalogo y hacerlo portable e independiente de la implementación de fondo debemos enfocarnos en la creación de los libros y estandarizar estas clases.
Ahora tenemos cuatro clases concretas (o cuatro objetos):
Diagrama del patrón Abstract Factory
Diagrama del patrón Abstract Factory

  • OReillyPHPBook, Crea un libro para la editorial OReilly de temática PHP
  • OReillyMySQLBook, Crea un libro para la editorial OReilly de temática MySQL
  • SamsMySQLBook, Crea un libro para la editorial Samas de temática PHP
  • SamsMySQLBook, Crea un libro para la editorial Samas de temática MySQL

Tenemos una clase abstracta AbstractBookFactory que define un método para crear cada editorial de libro. Luego las subclases editoriales OReillyBookFactory y SamsBookFactory implementan esos métodos para crear los libros correspondientes a las temáticas
Una clase abstracta AbstractBook que defina los métodos particulares de cada libro.
Las clases abstractas AbstractMySQLBook y AbstractPHPBook definen la temática particular de un libro.
Así, cada clase concreta a una temática extenderá de AbstractMySQLBook o de AbstractPHPBook y cada libro creado implementara los métodos de AbstractBook
Por ultimo tenemos la clase Catalogo que usaremos para instanciar el ejemplo y que no necesita comunicarse con las clases concretas, sino solo se comunica con sus clases abstractas.

Aplicabilidad

Estructura general del Patrón Abstract Factory
Estructura general del Patrón Abstract Factory
Usamos el patrón Abstract Factory cuando:
  • Un sistema debe ser independiente de cómo se crean, componen y representan sus objetos.
  • Un sistema debe configurarse para múltiples familias de objetos.
  • Una familia de objetos relacionados está diseñada para usarse en conjunto, y se necesita imponer esta restricción y
  • desea proporcionar una biblioteca de clases de objetos, y desea revelar solo sus interfaces, no sus implementaciones.

Participantes

  • AbstractFactory (AbstractBookFactory)
  • ConcreteFactory (OReillyBookFactory y SamsBookFactory)
  • AbstractProduct (AbstractMySQLBook y AbstractPHPBook)
  • ConcreteProduct (OReillyMySQLBook, OReillyPHPBook, SamsMySQLBook, SamsPHPBook)
  • Cliente (Catalogo)

Colaboraciones

En tiempo de ejecución se necesita una sola instancia de ConcreteFactory. Si el Cliente necesita crear diferentes productos (libros), debería usar diferentes ConcreteFactory.
AbstractFactory delega la creación de los productos (libros) a sus subclases.

Consecuencias

El patrón Abstract Factory tiene los siguientes beneficios y responsabilidades:
  • Aísla las clases concretas. Encapsulando la responsabilidad de la creación de productos y aislando al cliente de la implementación
  • Hace que sea fácil intercambiar familias de productos. Nos permite cambiar rápidamente entre ConcreteFactorys pues solo hay una instancia de esta clase en tiempo de ejecución.
  • Promueve la coherencia entre los productos. Los productos estan diseñados como una familia de de productos (Las editoriales y las temáticas son las familias)
  • Agregar nuevos tipos de productos es difícil. Debido a que la clase AbstractFactory fija el conjunto de productos a crear, agregar un nuevo producto significa modificar la clase y sus subclases.

Implementación

Algunas técnicas útiles para implementar este patrón son:
  • Usar el patrón Singleton. Solo se necesita una sola instancia por familia (OReillyBookFactory o SamsBookFactory)
  • AbstractFactory delega la responsabilidad a sus subclases de crear los productos. Se podría usar el patrón Factory Method o el patrón Prototype para esto.
  • Para agregar nuevos productos (libros) se podría agregar un parámetro a la clase AbstractFactory por medio de un solo método, así por medio del parámetro se decidiera que tipo de producto crear.

Código de Ejemplo

Por un lado de la estructura del patrón Abstract Factory tenemos la clase que define que libros crear.
/* Clase AbstractBookFactory */
namespace Blockpc\Patrones\AbstractFactory;
abstract class AbstractBookFactory {
abstract public function makePHPBook();
abstract public function makeMySQLBook();
}
Clase de la familia editorial OReilly y que extiende de AbstractBookFactory
/* Clase OReillyBookFactory */
namespace Blockpc\Patrones\AbstractFactory\OReilly;
use Blockpc\Patrones\AbstractFactory\AbstractBookFactory;
final class OReillyBookFactory extends AbstractBookFactory {
private $editorial = "OReilly";
public function makePHPBook() {
return new OReillyPHPBook;
}
public function makeMySQLBook() {
return new OReillyMySQLBook;
}
}
Clase de la familia editorial Sams y que extiende de AbstractBookFactory
/* Clase SamsBookFactory */
namespace Blockpc\Patrones\AbstractFactory\Sams;
use Blockpc\Patrones\AbstractFactory\AbstractBookFactory;
final class SamsBookFactory extends AbstractBookFactory {
private $editorial = "Sams";
public function makePHPBook() {
return new SamsPHPBook;
}
public function makeMySQLBook() {
return new SamsMySQLBook;
}
}
Por el otro lado de la estructura, tenemos una clase que define las propiedades comunes de los libros
/* Clase AbstractBook */
namespace Blockpc\Patrones\AbstractFactory;
abstract class AbstractBook {
abstract public function getAuthor();
abstract public function getTitle();
}
Tenemos una clase para los libros con temática sobre PHP
/* Clase AbstractPHPBook */
namespace Blockpc\Patrones\AbstractFactory;
abstract class AbstractPHPBook extends AbstractBook {
protected $tematica = "PHP";
}
Y una clase para los libros con temática sobre MySQL
/* Clase AbstractMySQLBook */
namespace Blockpc\Patrones\AbstractFactory;
abstract class AbstractMySQLBook extends AbstractBook {
protected $tematica = "MySQL";
}
Luego tenemos los cuatro objetos (libros)
Libro de editorial OReilly sobre PHP
/* Clase OReillyPHPBook */
namespace Blockpc\Patrones\AbstractFactory\OReilly;
use Blockpc\Patrones\AbstractFactory\AbstractPHPBook;
class OReillyPHPBook extends AbstractPHPBook {
/* Acá va el código y la implementación de AbstractPHPBook */
}
Libro de editorial OReilly sobre MySQL
/* Clase OReillyMySQLBook */
namespace Blockpc\Patrones\AbstractFactory\OReilly;
use Blockpc\Patrones\AbstractFactory\AbstractMySQLBook;
class OReillyMySQLBook extends AbstractMySQLBook {
/* Acá va el código y la implementación de AbstractPHPBook */
}
Libro de editorial Sams sobre MySQL
/* Clase SamsMySQLBook */
namespace Blockpc\Patrones\AbstractFactory\Sams;
use Blockpc\Patrones\AbstractFactory\AbstractMySQLBook;
class SamsMySQLBook extends AbstractMySQLBook {
/* Acá va el código y la implementación de AbstractPHPBook */
}
Libro de editorial Sams sobre PHP
/* Clase SamsPHPBook */
namespace Blockpc\Patrones\AbstractFactory\Sams;
use Blockpc\Patrones\AbstractFactory\AbstractPHPBook;
class SamsPHPBook extends AbstractPHPBook {
/* Acá va el código y la implementación de AbstractPHPBook */
}
Por ultimo tenemos al cliente, nuestra clase Catalogo que por medio del método pruebaPatronAbstractFactory nos devuelva los libros.
/* Clase Catalogo */
namespace Blockpc\Clases;
use Blockpc\Patrones\AbstractFactory\AbstractBookFactory;
final class Catalogo {
public function __construct() {
echo "Iniciando Catalogo...<br>";
}
public function pruebaPatronAbstractFactory(AbstractBookFactory $bookFactoryInstance) {
$phpLibroUno = $bookFactoryInstance->makePHPBook();
$this->escribir('Primer Libro PHP Autor: '.$phpLibroUno->getAuthor());
$this->escribir('Primer Libro PHP Titulo: '.$phpLibroUno->getTitle());
$phpLibroDos = $bookFactoryInstance->makePHPBook();
$this->escribir('Segundo Libro PHP Autor: '.$phpLibroDos->getAuthor());
$this->escribir('Segundo Libro PHP Titulo: '.$phpLibroDos->getTitle());
$mySqlLibro = $bookFactoryInstance->makeMySQLBook();
$this->escribir('MySQL Autor: '.$mySqlLibro->getAuthor());
$this->escribir('MySQL Titulo: '.$mySqlLibro->getTitle());
$this->escribir('');
}
private function escribir(String $linea): void {
echo $linea."<br/>";
}
public function __destruct() {
echo "... Catalogo completado.<br>";
}
}
Instanciamos un catalogo (cliente) y llamamos al método pruebaPatronAbstractFactory pasandole una instancia de alguna clase ConcreteFactory
/* index.php */
$catalogo = new Catalogo;
$bookFactoryInstance = new OReillyBookFactory;
$catalogo->pruebaPatronAbstractFactory($bookFactoryInstance);
$bookFactoryInstance = new SamsBookFactory;
$catalogo->pruebaPatronAbstractFactory($bookFactoryInstance);

Usos Conocidos

En sistemas en donde podamos agrupar objetos similares en una misma familia. En nuestro caso, las editoriales serian las familias para nuestros libros reunidos bajo diversas temáticas.

Patrones Relacionados

Como se ha comentado, los patrones relacionados serian: el patrón Factory Method, el patrón Prototype y el patrón Singleton.

Ultimas Consideraciones

Las clases abstractas AbstractBookFactory y AbstractBook se podrían intercambiar por Interfaces fácilmente puesto que estas clases solo definen contratos.

El código fuente de este articulo lo puedes descargar de acá

Saludos y hasta el próximo articulo.

Etiquetas patrones diseño solid

Ultima actualización Jueves 05 de Julio, 2018




Agregar Comentario