Daniel Segovia

Blog personal

Archive for the ‘6.3 Patrón Singleton’ Category

Patrón de diseño Singleton

Hacer un comentario

El patrón de diseño Singleton tiene como finalidad asegurar que sólo se pueda crear una instancia de determinada clase.

Es muy común ver este patrón aplicado en las conexiones a la base de datos, no es necesario tener 10, 20 o 30 conexiones abiertas a la misma base de datos, con una es más que suficiente. Entonces cuando tenemos un proyecto en el cual varias clases harán uso de la base de datos las instancias las haremos con Singleton y esto nos asegurará tener 1 sola instancia del objeto lo cual reducirá ampliamente los consumos de memoria.

La lógica del patrón es simple, sí el objeto nunca fue creado éste es instanciado y devuelto pero sí previamente había sido instanciado el patrón devolverá objeto.

Veamos un ejemplo de un contador, noten como en la implementación se crean varias instancias del mismo objeto pero la propiedad que lleva la cuenta siempre conserva el mismo valor, naturalmente esto se debe a que el objeto siempre es el mismo.

<?php 
 
class Singleton {
   private static $instancia;
   private $contador;
   protected $cantidad;
 
 
   private function __construct(){
      echo "Primera Instancia de " . __CLASS__ . " ha sido creada\n<br/>";
      $this->contador = 0;
      $this->setCantidad(10);
   }
 
   public static function getInstance() {
      if (  !self::$instancia instanceof self) {
         self::$instancia = new self;
      }
      return self::$instancia;
   }
 
   public function getCantidad(){
      return $this->cantidad;
   }
 
   public function setCantidad($value){
      $this->cantidad = intval($value);
   }
 
   public function incrementar(){
      return $this->contador+= $this->getCantidad();
   }
 
   public function disminuir() {
      return $this->contador-= $this->getCantidad();
   }
}
?>
 
<?php
$primeraInstancia = Singleton::getInstance();
echo "Primera Instancia (+): " . $primeraInstancia->incrementar() . "\n<br/>";
echo "Primera Instancia (+): " .$primeraInstancia->incrementar() . "\n<br/>";
echo "Primera Instancia (+): " .$primeraInstancia->incrementar() . "\n<br/>";
$segundaInstancia = Singleton::getInstance();
echo "Segunda Instancia (-): " .$segundaInstancia->disminuir() . "\n<br/>";
echo "Segunda Instancia (+): " .$segundaInstancia->incrementar() . "\n<br/>";
$terceraInstancia = Singleton::getInstance();
echo "Tercera Instancia (-): " .$terceraInstancia->disminuir() . "\n<br/>";
?>

Resultado

Primera Instancia de Singleton ha sido creada
Primera Instancia (+): 10
Primera Instancia (+): 20
Primera Instancia (+): 30
Segunda Instancia (-): 20
Segunda Instancia (+): 30
Tercera Instancia (-): 20

Ahora para estar bien seguros de tener una sola instancia, debemos prevenir que el objeto sea clonado y también que sea serializado y deserializado.

Para evitar la clonación agregaremos el método __clone a nuestra clase y para la serialización el método __wakeup
Nuestra clase quedará de la siguiente manera

<?php 
 
class Singleton {
   private static $instancia;
   private $contador;
   protected $cantidad;
 
 
   private function __construct(){
      echo "Primera Instancia de " . __CLASS__ . " ha sido creada\n<br/>";
      $this->contador = 0;
      $this->setCantidad(10);
   }
 
   public static function getInstance() {
      if (  !self::$instancia instanceof self) {
         self::$instancia = new self;
      }
      return self::$instancia;
   }
 
   public function getCantidad(){
      return $this->cantidad;
   }
 
   public function setCantidad($value){
      $this->cantidad = intval($value);
   }
 
   public function incrementar(){
      return $this->contador+= $this->getCantidad();
   }
 
   public function disminuir() {
      return $this->contador-= $this->getCantidad();
   }
 
   public function __clone(){
      trigger_error("Operación Invalida: No es posible clonar una instancia de ". get_class($this) ." class.", E_USER_ERROR );
   }
 
   public function __wakeup(){
      trigger_error("Operación Invalida: No es posible deserializar una instancia de ". get_class($this) ." class.", E_USER_ERROR );
   }
}
?>

Ahora sí tenemos asegurado que la clase Singleton solo estará instanciada 1 vez.

Written by Daniel Segovia

diciembre 21st, 2011 at 1:10 pm