Cuando nos acostumbremos a implementar patrones, nos daremos cuenta que la mayoría de los diseños cumplen con este principio.

El gran beneficio de este patrón es la flexibilidad para aplicar cambios y para reusar código, facilitando además la alteración del "algoritmo base" de la solución que estamos implementando. El algoritmo está implementado en un único método y si debemos modificarlo este cambio impactará en todo el sistema de forma controlada, sin tener que modificar individualmente a las clases concretas (donde se encuentra la implementación de bajo nivel). Y sobre el caso de reuso, la "clase padre" de la herencia puede contener un "comportamiento por defecto" que todas las "clases hijas" van a heredar, y solo sobreescribirán el método correspondiente cuando necesiten cambiar su comportamiento según nuestros requerimientos.
Contexto del ejemplo
Necesitamos una estructura que nos permita generar listados que cumplen el siguiente algoritmo: imprimir primero la información del cabezal, luego el cuerpo y finalmente el pie del documento. Cada clase derivada vuelve a implementar el método que hereda de la "clase padre" cada vez que necesite cambiar el comportamiento base. De la misma forma, si deseamos agregar un nuevo tipo de listado, no necesitaremos modificar el código de nuestra solución, solo crear una clase y heredar de la clase padre ("abierto a la extensión").
Por demás está decir que el "foco de cambio" es claro: si tenemos un sistema que provee listados de distinto tipo, es muy probable que con el tiempo surjan modificaciones en el comportamiento general (cambia la estructura o el diseño de nuestra hoja de impresión) o se agregan nuevos casos a los existentes (un nuevo tipo de listado).
Se creó una clase Listado que será la única estructura que contendrá verdaderamente el algoritmo de la solución (dentro del método imprimir) y una serie de métodos que pertenecen *solo* a la lógica interna del algoritmo.
// Archivo: Listado.class.php
class Listado {
// Algoritmo base
public function imprimir(){
$this->cabezal();
$this->cuerpo();
$this->pie();
}
// Contenido inicial para cada parte del
// algoritmo
protected function cabezal(){
echo "Listado - Cabezal";
}
protected function cuerpo(){
echo "Listado - Cuerpo";
}
protected function pie(){
echo "Listado - Pie";
}
}
?>
// Archivo: Comun.class.php
require_once 'Listado.class.php';
class Comun extends Listado{
// Altero el comportamiento base
// de una parte del algoritmo, el "pié"
protected function pie(){
echo "Comun - pie";
}
}
?>
// Archivo: Avanzado.class.php
require_once 'Listado.class.php';
class Avanzado extends Listado{
// En este caso, modifico completamente
// el contenido de los elementos que
// comprenden el algoritmo, pero no
// quiere decir que pueda cambiar
// el orden del mismo (esto se mantiene
// controlado en la clase base "Listado")
protected function cabezal(){
echo "Avanzado - cabezal";
}
protected function cuerpo(){
echo "Avanzado - cuerpo";
}
protected function pie(){
echo "Avanzado - pie";
}
}
?>
// Archivo: Estandar.class.php
require_once 'Listado.class.php';
class Estandar extends Listado {
// En este caso, no hacemos nada
// y se reaprovecha todo el contenido
// de la "clase base"
}
?>
// Archivo: index.php
require_once 'Listado.class.php';
require_once 'Comun.class.php';
require_once 'Avanzado.class.php';
require_once 'Estandar.class.php';
abstract class Index {
public static function run(){
self::imprimir(new Comun());
self::imprimir(new Avanzado());
self::imprimir(new Estandar());
}
// Solo pueden pasar como parámetros
// objetos que sean del tipo "clase base",
// logrando efectuar un "contrato de diseño"
// (para poder imprimir debes heredar de la
// clase "Listado").
private static function imprimir(Listado $b){
$b->imprimir();
}
}
Index::run();
?>
Detalles a tener en cuenta
La definición del diseño del patrón dice que los métodos que se utilizan son parte del algoritmo y están con la visibilidad "protegida" y no "privada". Si fuera así, los métodos no podrían ser accesibles desde otras clase de la jerarquía, impidiendo que puedan sobreescribirse.
Si fuera "públicos" los métodos, podrían ser accedidos directamente desde la clase "cliente" (en este caso "Index") y acceder a partes del algoritmo, lo cual solo nos interesa que lo ejecuten de forma integra. Para este último caso está disponible el método "imprimir" de la clase "Listado".
Y como último detalle, no hace falta instanciar clases que no se necesitan o no deban hacerlo ... para eso se define clases "abstractas" que impiden la creación de instancias y a los métodos como "estáticos", lo que impide que puedan ser usados en el contexto de una instancia.
Dudas, sugerencias, correcciones, insultos, en los comentarios, plis ;-)
Más información
Wikipedia
Do Factory
0 comentarios:
Publicar un comentario