Daniel Segovia

Blog personal

Archive for the ‘6 – Patrones’ Category

Patrón Proxy

Hacer un comentario

El patrón Proxy en PHP es sencillo de entender, es utilizado como intermediario para acceder a un objeto llamado SujetoReal.
Básicamente, tenemos un objeto Proxy que actúa como un sustituto de un objeto SujetoReal. Se realiza una solicitud al Proxy y éste es el encargado de transmitirla a SujetoReal
El objeto Proxy posee una referencia al objeto SujetoReal y controla el acceso a sus métodos y propiedades, introduciendo las funcionalidades que cree necesarias.

Posibles tipos de Proxies

  • Proxy Remoto: Cuando el objeto proxy está en una dirección y el objeto real está en otra. En este caso proxy puede funcionar como corta fuegos (firewall). Es muy común ver este esquema con los juegos en línea donde se necesita el mismo objeto en diferentes lugares al mismo tiempo.
  • Proxy Virtual: Puede almacenar en caché información, de modo que el acceso al objeto real puede ser postergada
  • Proxy de protección: Mantiene la protección de la solicitud al objeto real hasta que la solicitud es verificada por el servidor proxy de protección

Veamos un ejemplo sencillo

<?php
abstract class ISujeto{
    abstract protected function request();
}
 
 
class Proxy extends ISujeto{
    private $SujetoReal;
 
    public function request(){	
        echo "agregando funciona al inicio <br />";
        $this->SujetoReal = new SujetoReal();
        $this->SujetoReal->request();	
        echo "agregando funciona al final <br />";
    }
}
 
class SujetoReal extends ISujeto{
    protected function request(){
        echo "Ejecutando request en " . get_class() . "<br />";
    }
}
 
//implementacion
class Usuarios{
    private $proxy;
 
    public function __construct(){
        $this->proxy = new Proxy();
    }
 
    public function hacerX(){
        $this->proxy->request();
    }
}
 
$objeto = new Usuarios;
$objeto->hacerX();
 
?>

Resultado

agregando funciona al inicio
Ejecutando request en SujetoReal
agregando funciona al final

Como podemos ver, agregamos un mensaje al inicio y uno al final de la llamada al SujetoReal.
Esto es una introducción al patrón Proxy y el ejemplo intenta demostrar fácilmente una estructura del patrón y una implementación. En proyectos grandes es un común ver este tipo de esquemas.

Written by Daniel Segovia

enero 23rd, 2012 at 1:08 pm

Patrón Modelo Vista Controlador

Hacer un comentario

MVC son las siglas del patrón de arquitectura Modelo Vista Controlador (model view controller en inglés) que se encarga de separar los datos en una aplicación.

Podemos ver fácilmente MVC en el diseño de una página web. Por un lado tenemos el resultado final, el HTML, en esta caso la vista, por otro lado tenemos un montón de información guardada en nuestra base de datos, toda la interacción con ella será procesada por el modelo y la toma de decisiones, por ejemplo mostrar distintos contenidos para diferentes niveles de usuarios, estará a cargo del controlador

  • Modelo: El modelo se encarga del acceso a la información, independientemente de donde y como este guardada, éste será el encargado de retornar, en un formato especifico, la información que estén solicitando. Los datos o información en principio no tendrían importancia para nuestro controlador y vista, el modelo extraerá lo necesario ya sea de un archivo de texto, una base de datos, un xml o de algún otro medio
  • Vista: La vista tiene como objetivo visualizar todo lo previamente procesado. Suponiendo que estamos desarrollando el juego del ta-te-ti, por lo general un jugador juega con la “X” y el otro con la “O”, nuestra vista puede mostrar esto o “X” e “Y” o “W” y “Z” para cada jugador, también cada jugador podría tener una imagen asignada. Estos cambios serán fácil implementando MVC ya que la lógica del juego estará en otras capas de la aplicación
  • Controlador: El controlador será el encargado de tomar decisiones. Cualquier tipo de camino que se siga el flujo del sistema será por que el controlador desviará éste flujo según la decisión que tome. Continuando con el ta-te-ti el controlador dará turno al siguiente jugador o dirá cuando el juego esta terminado

Bueno, empecemos con el ejemplo en código.
Aquí mostraré 4 archivos, la versión completa pueden descargarla aquí

Aquí el index.php, básicamente este se encarga de juntar todas las partes, recibe dos parámetro por GET, uno es el controlador y el otro la acción (el método) que debe ejecutar.

Luego de algunas validaciones simples instancia el controlador y ejecuta la acción.

<?php
//index.php
define('CARPETACONTROLADORES', "controladores/");
define('CARPETAMODELOS', "modelos/");
define('CARPETAVISTAS', "vistas/");
 
 
if(!empty($_GET['controlador'])){
    $controlador = $_GET['controlador'];
    $file = CARPETACONTROLADORES . $controlador . ".php";
 
    if(is_file($file)){
        require_once $file;
        $objecto = new $controlador;
    }
    else{
          die('El controlador no existe');
    }
}else{
          die('No ha definido un controlador');
}
 
if(!empty($_GET['accion'])){
    $accion = $_GET['accion'];
    if(!method_exists($controlador, $accion)){
        die('El metodo '.$accion.' no existe en el controlador ' . $controlador);
    }
}else{
          die('No ha definido una accion');
}
 
$objecto->$accion();
 
?>

Controlador

<?php
//usuarios.php
require_once CARPETACONTROLADORES . "controlador.php";
 
class usuarios extends controlador {
 
    function __construct(){
        require_once CARPETAMODELOS . "modeloUsuarios.php";
        $this->modelo = new modeloUsuarios;
    }
 
    function listar(){
        $usuarios = $this->modelo->listar();
        require_once CARPETAVISTAS . "usuariosListar.php";
 
    }
}
 
?>

Modelo

<?php
//modeloUsuarios.php
require_once CARPETAMODELOS . "modelo.php";
 
class modeloUsuarios extends modelo{
 
    function __construct(){
        parent::__construct();
    }
 
    function listar(){
        $query = "SELECT nombre, apellido FROM usuarios";
        $result = $this->mysqli->query($query);
        return $result;
    }
}
 
?>

Por sí no vieron el link más arriba :D
Descarguen el ejemplo funcionando desde aquí

Written by Daniel Segovia

enero 19th, 2012 at 4:12 pm

Patrón de estrategia

Hacer un comentario

Cuando tenemos un algoritmo que por algún motivo puede llegar a cambiar en tiempo de ejecución o bien su implementación podemos trabajar con el patrón de estrategia para que éste decida que camino tomar.
Básicamente consiste en definir una interfase con los métodos del algoritmo para luego plantear cada uno de éstos en las clases que implementen la interfase.
Cada algoritmo estará encapsulado y será intercambiable independientemente de los clientes que lo utilicen.

Veamos el siguiente ejemplo, tenemos un array con el nombre de un producto y el precio. Para algunos clientes es conveniente mostrarlos en orden alfabética y en otros en orden ascendente de precio.

<?php
 
interface estrategia{
    public function ordenar($productos);
}
 
class OrdenarPorNombre implements estrategia{
 
    public function ordenar($productos){
        ksort($productos);
        return $productos;
    }
 
}
 
class OrdenarPorPrecio implements estrategia{
 
    public function ordenar($productos){
        asort($productos);
        return $productos;
    }
 
}
 
class usuarios {
 
    private $productos;
 
    public function getProductos(){
        return $this->productos;
    }
 
    public function setProductos($productos){
        $this->productos = $productos;
    }
 
    public function mostrar($estrategia){
        print_r($estrategia->ordenar($this->getProductos()));
    }
 
}
 
$productos = array('Remera'=>20, 'Campera'=>50, 'Patalon'=>35, 'Gorro'=>10);
 
$u = new usuarios;
$u->setProductos($productos);
$u->mostrar(new OrdenarPorNombre);
$u->mostrar(new OrdenarPorPrecio);
 
?>

Resultado

Array
(
    [Campera] => 50
    [Gorro] => 10
    [Patalon] => 35
    [Remera] => 20
)
 
Array
(
    [Gorro] => 10
    [Remera] => 20
    [Patalon] => 35
    [Campera] => 50
)

Written by Daniel Segovia

enero 9th, 2012 at 4:43 pm

Patrón Observador

Hacer un comentario

El patrón observador es sencillo de entender y más fácil de ver cuando es necesario.
Tendremos 2 objetos, por un lado el observador y por el otro el observado.
El observador debe ver cuando el observado realiza algún cambio y tomar determinada acción.
El modelos antiguos el observador miraba constantemente al observado para ver cuando éste cambiada, el problema de éste modelo es que había que mirar constantemente al observado para ver cuando realizaba una modificación.
Con el patrón observador cambiaron un poco los roles, tenemos el mismo esquema, observador y observado, la diferente es que observador no estará “mirando” todo el tiempo a observado para ver cuando hay un cambio, sino que éste último le avisará mediante una notificación a su observador cuando haga efectivo dicho cambio.

En un ejemplo de la vida cotidiana:

- Un padre ve como su niño anda en bicicleta, él esta ateto el 100% del tiempo mirando que no se golpee, sí un accidente ocurriese el padre se enteraría al instante ya que ve lo que sucedió. Aquí vemos como el observador está monitoreando constantemente al observado.
- Un niño esta andando en bicicleta y al tener un incidente éste avisa a su padre. Aquí vemos como el observado notifica a su observador en determinado evento.

Vamos a los papeles, aquí el código
Separaremos las clases de la implementación, estará en 2 archivos, modelo.php e implementacion.php

<?php
//modelo.php
abstract class observable{
 
    protected $observadores;
 
    public function __construct(){
        $this->observadores = array();
    }
 
    public function registrarObservador($observador){
        if(!in_array($observador, $this->observadores)){
            array_push($this->observadores, $observador);
        }
    }
 
    public function eliminarObservador($observador){
        if(in_array($observador, $this->observadores)){
            $key = array_search($observador, $this->observadores);
            unset($this->observadores[$key]);
        }
    }
 
    abstract public function notificarObservador();
 
}
 
 
interface observador{
    public function notificar($remitente, $parametro);
}
 
class Usuario extends observable{
 
    public $parametro;
 
    public function __construct(){
        parent::__construct();
    }
 
    public function notificarObservador(){
        if(count($this->observadores)  > 0){
            foreach ($this->observadores as $observador){
                $observador->notificar($this, $this->parametro);
            }
        }else{
            echo "No hay observadores<br />";
        }
    }
 
    public function setParametro($value){
        $this->parametro = $value;
        $this->notificarObservador();
    }
 
    public function getParametro(){
        return $this->parametro;
    }
}
 
class Log implements Observador{
    public function notificar($remitente, $parametro){
        echo "El objeto " . get_class($remitente) . " ha cambiado la propiedad `parametro` al valor de '$parametro' a las " . date('H:i:s', time()) . "<br />";
    }
}
 
class LogDB implements Observador{
    public function notificar($remitente, $parametro){
        echo "El objeto " . get_class($remitente) . " ha guardado la propiedad `parametro` por valor de '$parametro' en la base de datos<br />";
    }
}
 
class LogEmail implements Observador{
    public function notificar($remitente, $parametro){
        echo get_class($remitente) . " notifica un cambio y ha sido enviado por mail<br />";
    }
}
?>

Vamos a dividir la explicación de modelo.php en 4

  • Definimos una clase abstracta observable, todas las clases que extiendan de ésta podrán ser observadas, también podrán registrar y eliminar observadores y deberán implementar la notificación
  • Definimos una interfaz observador, todos los observadores implementarán ésta interfaz y estarán obligadas a poseer el método notificar, sí bien éste paso podría pasarse por alto es una muy buen practica
  • Definimos la clase que va a ser observada, en este ejemplo usamos una clase llamada Usuario y ésta notificará a sus observadores cuando la propiedad método haya cambiado su valor
  • Por último definimos los observadores que implementan la interfaz y todos poseen el método notificar, aquí definimos 3 observadores, un muestra un mensaje, otro guarda en base de datos y el último da un aviso por mail

Aquí la implementación, veremos diferentes maneras en las implementaciones.

Implementación 1:

<?php
//implementacion1.php
$ob = new Usuario;
$ob->setParametro('Daniel');
echo "Parametro: " . $ob->getParametro() . "<br />";
?>
<!--resultado-->
No hay observadores
Parametro: Daniel

Implementación 2:

<?php
//implementacion2.php
$ob = new Usuario;
$ob->registrarObservador(new Log);
$ob->setParametro('Marcos');
echo "Parametro: " . $ob->getParametro() . "<br />";
?>
<!--resultado-->
El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Marcos' a las 18:40:46
Parametro: Marcos

Implementación 3:

<?php
//implementacion3.php
$ob = new Usuario;
$ob->registrarObservador(new Log);
$ob->registrarObservador(new LogDB);
$ob->registrarObservador(new LogEmail);
$ob->setParametro('Federico');
echo "Parametro: " . $ob->getParametro() . "<br />";
?>
<!--resultado-->
El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Federico' a las 18:42:08
El objeto Usuario ha guardado la propiedad `parametro` por valor de 'Federico' en la base de datos
Usuario notifica un cambio y ha sido enviado por mail
Parametro: Federico

Implementación 4:

<?php
//implementacion4.php
$ob = new Usuario;
$ob->registrarObservador(new Log);
$ob->registrarObservador(new LogDB);
$ob->registrarObservador(new LogEmail);
$ob->setParametro('Hugo');
echo "Parametro: " . $ob->getParametro() . "<br />";
 
sleep(2);
 
$ob->eliminarObservador(new LogDB);
$ob->setParametro('Diego');
echo "Parametro: " . $ob->getParametro() . "<br />";
?>
<!--resultado-->
El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Hugo' a las 18:43:45
El objeto Usuario ha guardado la propiedad `parametro` por valor de 'Hugo' en la base de datos
Usuario notifica un cambio y ha sido enviado por mail
Parametro: Hugo
El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Diego' a las 18:43:47
Usuario notifica un cambio y ha sido enviado por mail
Parametro: Diego

Written by Daniel Segovia

diciembre 28th, 2011 at 6:45 pm

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

Patrón de diseño Factory

Hacer un comentario

El patrón de diseño factory, está basado en la instancia de objetos en tiempo de ejecución.

En pequeños proyectos no es frecuente usar éste patrón pero cuando los proyectos son grandes o trabajen muchas personas es muy común implementarlo.

Wikipedia posee una explicación perfecta

Factory Method consiste en utilizar una clase constructora (al estilo del Abstract Factory) abstracta con unos cuantos métodos definidos y otro(s) abstracto(s): el dedicado a la construcción de objetos de un subtipo de un tipo determinado. Es una simplificación del Abstract Factory, en la que la clase abstracta tiene métodos concretos que usan algunos de los abstractos; según usemos una u otra hija de esta clase abstracta, tendremos uno u otro comportamiento.

He aquí un ejemplo con varias clases para conectarse a diferentes base de datos, sin importar donde desee conectarme concentraré la instancia en una clase llamada BaseDeDatos

<?php
 
class MySQL{
  public function __construct(){
    echo "Instancio MySQL";
  }
}
 
class PostgreSQL{
  public function __construct(){
    echo "Instancio PostgreSQL";
  }
}
 
abstract class BaseDeDatos{
    public static function cargar($tipo){
        try {
            if (class_exists($tipo)) {
                return new $tipo;
            } else {
                throw new Exception("No existe la clase '$tipo'");
            }
        } catch (Exception $e) {
            echo 'Excepción capturada: ',  $e->getMessage(), "\n";
        }
    }
}
 
BaseDeDatos::cargar("MySQL");
echo "<br >";
BaseDeDatos::cargar("PostgreSQL");
echo "<br >";
BaseDeDatos::cargar("Oracle");
?>

Resultado

Instancio MySQL
Instancio PostgreSQL
Excepción capturada: No existe la clase 'Oracle'

Como resumen podemos decir que todo queda centralizado en la clase BaseDeDatos, y como puede observarse realiza una pequeña validación antes de realizar la instancia.

Written by Daniel Segovia

diciembre 21st, 2011 at 11:30 am

Introducción a patrones de diseño en PHP

Hacer un comentario

Me resulto un tanto difícil comenzar la introducción para éste capítulo, simplificar la explicación de los patrones de diseño no fue tarea sencilla, la pregunta obligada es:
¿Qué son los patrones de diseño?
Para esto busqué algunos conceptos que me guíen en la explicación y me tope en muchos lugares con la siguiente definición.
“Los patrones de diseño son el esqueleto de las soluciones a problemas comunes en el desarrollo de software”
Explicado con mis palabras, éstos ofrecen soluciones simples a problemas comunes en el desarrollo de software.
Con la gran cantidad de diseños de aplicaciones hay problemas que se repiten frecuentemente, entonces éstos responden a un cierto patrón.
Los patrones de diseño son un conjunto de buenas prácticas que pueden nos aliviarán el trabajo en muchas situaciones cuando realizamos una aplicación orientada a objetos

Sí vemos la introducción de éste capítulo como un problema y la frase que hallé como una solución ya probada podríamos decir que encontré un patrón de diseño para mi problema, a grandes rasgos éste es el concepto.

Written by Daniel Segovia

diciembre 16th, 2011 at 1:31 pm

Posted in 6.1 Introducción