http://migueljaque.com
Notas sobre Metodologías Ágiles
Estás en:   Inicio Patrones Otros Singleton Derivado
Singleton Derivado PDF Imprimir E-mail
Viernes, 25 de Abril de 2008 11:44

Vamos a profundizar en el patrón Singleton, porque ¿qué ocurre si lo que queremos es aplicar el patrón de Singleton a una clase derivada?

Nota: El Singleton Derivado no es un patrón propiamente dicho. Ningún gurú (que yo sepa) lo ha definido como tal. Es simplemente una idea que se me ha ocurrido para resolver un problema de Diseño. Si tienes una idea mejor para resolver este problema, por favor, dímelo.

El Problema

Tenemos una clase "Padre" que no es Singleton. Y lo que queremos es aplicar el patrón de Singleton a una clase "Hija" derivada de la clase "Padre"... ¿ningún problema? ¡¡Todo lo contrario!!

Si intentamos hacer esto:

 <?php
class Singleton extends Non-Singleton{
private function __construct(){
}
}
?>

Nos encontramos con un error del compilador. En el caso de PHP5, el error es

Fatal error: Access level to Singleton::__construct() must be public (as in class Non-Singleton)

El origen de este error está en las restricciones a la derivación. Al derivar, no se puede limitar la visibilidad de los métodos heredados. Al contrario de lo que ocurre con los atributos, los métodos deben conservarse para garantizar que la clase derivada puede comportarse como cualquier otra instancia de la clase Padre.

Entonces... ¿cómo creamos un Singleton Derivado?

Soluciones

Se me ocurren dos formas de solucionar el problema. Y debo anticipar que ninguna es buena.

Usando un Semáforo

La primera idea es utilizar un semáforo para evitar la construcción de la instancia si esta ya existe. El problema es que cualquier llamada al constructor (que no podemos restringir) devolverá una referencia al objeto creado. Lo único que podemos hacer es detectar que la instancia ya existe y lanzar una excepción:

 <?php
class Singleton extends Non-Singleton{

private static $instancia;
private static $semaforo = false;

public function __construct(){
if (!self::$semaforo)
		throw new Exception ("No llames al  constructor. Usa verInstancia");
//código de construccion...
self::$semaforo = false;
}

public function verInstancia(){
if (self::$instancia === null){
self::$semaforo = true;
self::$instancia = new self;
}
return self::$instancia;
}
}
?>

El problema de esta solución es que no es multihilo (aunque eso puede no ser un problema en muchas aplicaciones). Y tampoco parace muy elegante.

La segunda solución tampoco es ninguna maravilla:

Aprovechando el Lenguaje

Esta solución es más elegante, pero está pillada por los pelos. Aprovecha una característica de PHP5, por lo que puede no ser aplicable a otros lenguajes.

El caso es que en PHP4 los constructores se definían como métodos con el mismo nombre que la clase. Podemos aprovecharlo para crear la clase padre (Non-Singleton) utilizando como constructor el método antiguo. De esta forma nos saltamos la restricción de visibilidad de los métodos sobreescritos y podemos declarar el constructor como private. Una cosa así:

 <?php
class Non-Singleton{
public function Non-Singleton(){
//código de construcción...
}
}
class Singleton extends Non-Singleton{

private static $instancia;

private function __construct(){
//código de construccion...
}

public function verInstancia(){
if (self::$instancia === null)
self::$instancia = new self;
return self::$instancia;
}
}
?>

Lo dicho, no es para estar orgulloso. Por eso, si tienes alguna idea mejor, por favor, dímelo.

Actualizado ( Viernes, 25 de Abril de 2008 12:25 )
 

Apoyo a la Cultura Libre: Si eres legal ¡¡COMPARTE!!