Patrón Simple Factory en PHP5

Factory Method o Simple Factory

  
"Clase con la responsabilidad de crear objetos de otras clases. No delega en subclases y sus métodos pueden ser estáticos. Puede evolucionar en un Abstract Factory." [1]


Clasificación del patrón

Creacional.

Intención o problema que soluciona


Centraliza en una clase constructora la creación de objetos de un subtipo de un tipo determinado, ocultando al cliente la casuística para elegir el subtipo que crear.

Motivación

Muchos de ustedes pensaran: ¿Por qué complicarme tanto la vida utilizando un patrón de diseño, en lugar de instanciarla directamente $obj = new MiClase () ?

Hay un escenario principal en el que puede resultar útil.

Flexibilidad en tiempo de ejecución: A veces es imposible elegir de antemano cuál objeto específico debe ser instanciado, ya que la elección de los objetos a utilizar puede depender de algo en el entorno de ejecución.

Aplicabilidad

  1. Una clase no puede prever la clase de objetos que debe crear.
  2. Centralizar la creación de objetos.
  3. Proveer una interfaz para el cliente, permitiendo crear una familia de objetos sin especificar su clase.
Estructura



Implementación

La clase UserFactory tiene un método estático create, el cual recibe como parámetro un argumento y según el valor de este decide que clase instanciar (usualmente una subclase).

Código de Ejemplo en PHP5

Existen diferentes tipos y variantes de fábricas. En este artículo explicaré el Simple Factory.

  1. interface FactoryInterface {  
  2. static public function Create($name);  
  3. }  

  1. abstract class User {  
  2.   
  3.     protected $name = NULL;  
  4.       
  5.     public function __construct($name)  
  6.     {  
  7.         $this->name = $name;  
  8.     }  
  9.   
  10.     public function getName()  
  11.     {  
  12.         return $this->name;  
  13.     }  
  14.   
  15.     public function hasReadPermission()  
  16.     {  
  17.         return true;  
  18.     }  
  19.   
  20.     public function hasModifyPermission()  
  21.     {  
  22.         return false;  
  23.     }  
  24.   
  25.     public function hasDeletePermission()  
  26.     {  
  27.         return false;  
  28.     }  
  29.   
  30.     public function wantsFlashInterface()  
  31.     {  
  32.         return true;  
  33.     }  
  34. }  

  1. class GuestUser extends User { }  

  1. class CustomerUser extends User {  
  2.    function hasModifyPermission()  
  3.     {  
  4.         return true;  
  5.     }  
  6. }  

  1. class AdminUser extends User {  
  2.   
  3.     public function hasModifyPermission()  
  4.     {  
  5.         return true;  
  6.     }  
  7.   
  8.     public function hasDeletePermission()  
  9.     {  
  10.         return true;  
  11.     }  
  12.   
  13.     public function wantsFlashInterface()  
  14.     {  
  15.         return false;  
  16.     }  
  17. }  

  1. class UserFactory  implements FactoryInterface  {  
  2.       
  3.     private static $users = array('Arley'=>'admin''Michel'=>'guest',  
  4.                                   'Derick'=>'customer');  
  5.   
  6.    /** 
  7.     * Función de creación de usuarios. Recibe el tipo 
  8.     * de usario a crear y retorna una instancia valida 
  9.     * 
  10.     * @access public static 
  11.     * @param  string $name 
  12.     * @return object 
  13.     */  
  14.     static public function Create($name)  
  15.     {  
  16.         if (!isset(self::$users[$name])) {  
  17.            throw new Exception('El nombre de usuario '.$name.' es desconocido');  
  18.         }  
  19.         switch (self::$users[$name]) {  
  20.             case 'guest'return new GuestUser($name);  
  21.             case 'customer'return new CustomerUser($name);  
  22.             case 'admin'return new AdminUser($name);  
  23.             default:  
  24.             throw new Exception('Tipo de usario desconocido');  
  25.         }  
  26.     }  
  27. }  

  1. function boolToStr($b)  
  2. {  
  3.     if ($b == true) {  
  4.         return "Si\n";  
  5.     } else {  
  6.         return "No\n";  
  7.     }  
  8. }  
  9.   
  10. function displayPermissions(User $obj)  
  11. {  
  12.     print $obj->getName() . ' permiso:</br>';  
  13.     print 'Lectura: ' . boolToStr($obj->hasReadPermission()).'</br>';  
  14.     print 'Modificar: ' . boolToStr($obj->hasModifyPermission()).'</br>';  
  15.     print 'Escritra: ' . boolToStr($obj->hasDeletePermission()).'</br>';  
  16. }  
  17.   
  18. function displayRequirements(User $obj)  
  19. {  
  20.     if ($obj->wantsFlashInterface()) {  
  21.         print $obj->getName() . ' requiere Flash </br></br>';  
  22.     }  
  23. }  
  24.   
  25. $logins = array('Arley''Michel''Derick');  
  26.   
  27. foreach($logins as $login)  
  28. {  
  29.     displayPermissions(UserFactory::Create($login));  
  30.     print '</br>';  
  31.     displayRequirements(UserFactory::Create($login));  
  32. }  

Otros artículos sobre Patrones
  1. Patron Singleton en PHP
  2. Patrón de diseño Decorator en PHP
  3. Patrón Simple Factory en PHP
  4. Patrón Registry en PHP
  5. Patrón clásico de diseño web Modelo Vista Controlador (MVC) en PHP

Referencias bibliográficas
[1] León Welicki, «Patrones de Fabricación: Fábricas de Objetos». Consultado el 11 de septiembre de 2009.




5 comentarios:

  1. lo que no entiendo es como usas los metodos
    GuestUser
    CustomerUser
    y otros en la class UserFactory

    o sea a la clase UserFactory
    no le falta
    class UserFactory extends algo ... para poder usar esos metodos ?
    en esa marte me pierdo ...
    Saludos :-)

    ResponderEliminar
  2. me gusto el ejemplo. te olvidaste de implementar la interfaz en UserFactory lo unico.

    ResponderEliminar
  3. Despues de tanto tiempo ahora es que logro entender este patron mil gracias Arley

    ResponderEliminar
  4. Excelente artículo, pero esta implementación, no correspondería más a la del patrón de diseño "Strategy"? Sino es así, qué diferencias hay entre las dos? Un saludo!

    ResponderEliminar
  5. Compadre como se implementaria la Interfaz? salu2!

    ResponderEliminar