[PHP] El patrón de diseño (o antipatrón) singleton vs Inyección de dependencias ¿Que debo usar?

PHP es un lenguaje con el cual podemos usar herramientas avanzadas de desarrollo, algunas de estas herramientas son los patrones de diseño (Design Patterns),regularmente cuando empezamos a adentrarnos a esto de los patrones de diseño, uno de los primeros patrones que empezamos a usar es el patrón singleton, el cual garantiza un único acceso a cierto clase como una base de datos la implementación que yo uso/usaba es la siguiente:

<?php
/**
 *
 * Clase abstracta que define los metodos que implementaran los databaseManagers
 * @author Javier Lopez Lopez
 * @abstract
 *
 */
abstract class DatabaseManager{
	abstract public function findAll();
}

/**
 *
 * Clase Mysql Database manager (el singleton)
 * @author Javier Lopez Lopez
 *
 */
class Mysql extends DatabaseManager {

	private static $instance;

	private function __construct(){	}

	private function __clone(){ }

	public static function getInstance()
	{
		if(!(self::$instance instanceof self))
		{
			self::$instance = new self;
		}
		return self::$instance;
	}
	//...MORE CODE

	public function findAll()
	{
		//return all results
	}
}

/**
 * Usando el singleton
 */
class Controller {

	protected $database;	

	public function __construct()
	{
		//Como se que debo de incluirlo si nunca lo solicito en la ejecución de la clase
		//Ademas me limita a usar solo databasemanager de tipo MySQL
		//Evita que crezca el servicio no puedo agregar mas databases;
		$this->database = Mysql::getInstance();
	}  	

	public function getAll()
	{
		return 	$this->database->findAll();
	}
}

//Uso

$controller = new Controller();
$controler->getAll();
//nunca sabemos que adentro lleva un clase que se llama Mysql,
//entonces puede fallar, tambien no sabemos que se necesita Databasemanager

En la primera clase tenemos la implementación del singleton, y en la segunda clase en el constructor estamos llamando al singleton, sin embargo, caemos en una mala practica, la cual si vemos Mysql::getInstance() es como si fuera una llamada a una clase estática global, la cual es como si estuviéramos usando variables globales, lo cual es totalmente desaconsejado de usar, como comentan en mundogeek por las siguientes cosas:

  • El código es más difícil de entender
  • El código es más difícil de depurar
  • El código es más difícil de testear
  • El código es más difícil de mantener
  • El código es más difícil de reutilizar
  • Las variables globales matan gatitos

Extraído de: http://mundogeek.net/archivos/2011/07/12/variables-globales/

Entonces vemos que a pesar que de es posible usar Singleton no deberíamos de usarlo, solo en casos muy excepcionales, aunque es mejor buscar algún otro patrón de diseño.

Lo que deberíamos usar el la inyección de dependencias, que si bien es fácil de usar puede ser un poco complejo de entender:

La inyección de dependencias soluciona todos los items anteriores, y nos da una accesibilidad concreta a cada clase que necesitemos, si pasamos el código anterior a inyección de dependencia seria de la siguiente forma:

<?php
/**
 *
 * Clase abstracta que define los metodos que implementaran los databaseManagers
 * @author Javier Lopez Lopez
 * @abstract
 *
 */
abstract class DatabaseManager{
	abstract public function findAll();
}

/**
 * Clase Dependencia llamada Mysql
 * @author Javier Lopez Lopez
 */

class Mysql extends DatabaseManager {

	public function __construct()
	{
		//code of mysql
	}

	public function findAll()
	{
		//return all results
	}
}

/**
 * Usando el Inyección de dependencias
 */
class Controller {

	protected $database;

	public function __construct(DatabaseManager $database)
	{
		$this->database = $database;
	}  	

	public function getAll()
	{
	 	return $this->database->findAll();
	}
}

//Uso
//opción 1
$databaseManager = new Mysql();
$controller = new Controller($databaseManager);

//Opción 2
$controller = new Controller(new Mysql); 

//Opcion 3 cambiando de database manager sin problemas
$controller = new Controller(new SqlServer);
//suponiendo que tenemos un clase SqlServer

//resultado
$controller->getAll();

Como vemos es simple de implementar pero debemos estudiar bien el código, para que con esto no solo evitemos el uso de Singletons (“globales glorificadas”), si no que además podamos usar TDD(Desarrollo Guiado por Pruebas) sin ninguna complicación, además de tener un código claro y fácil de reutilizar componentes.

Como en este caso, podemos tener varios manejadores de base de datos como Mysql, SqlServer, etc, y podemos definir claramente cual necesitamos.

Como nota aclaratoria, yo no condeno el uso de singletons pero su uso debe de ser muy excepcional, de hecho Kohana Framework los usa pero para casos muy concretos de hecho casi todo su código usa inyección de dependencias.

One Response

Pingbacks/Trackbacks

Leave a Reply

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

*

*

Historico de entradas

febrero 2012
L M X J V S D
« ene    
 12345
6789101112
13141516171819
20212223242526
272829  

Ajaxman

Mi nombre es Javier, soy desarrollador web con especialización en PHP (avanzado), HTML, CSS y Javascript(Medio).

Me considero evangelizador de Kohana Framework, Mozilla Firefox y GNU/Linux Debian.

Estoy casado, y tengo dos hermosos hijos.

Todos los contenidos a menos que se exprese lo contrario estan bajo licencia Creative Commons.

Enlazanos!!

hit counters online counter