Introducción al patrón "peso mosca" con PHP 5
En pocas palabras, cuando se aplica el patrón "peso mosca", es posible especificar programáticamente que una clase concreta va a tener sólo un número predeterminado de instancias, las cuales son compartidas dentro de la misma implementación. Este simple concepto presenta un beneficio inmediato: previene instanciaciones innecesarias de la clase en cuestión, lo que da un claro aumento del rendimiento en sistemas que deben trabajar con cargas pesadas. Ciertamente, si vuelves a leer la definición anterior, está claro que una clase "peso mosca" se puede considerar un método directo para mantener la creación de objetos cuidadosamente balanceada. Sin embargo, esta sesión no está limitada a presentar la aburrida teoría de cómo funciona este patrón. Tendrás la oportunidad de aprender y probar varios ejemplos prácticos relacionados con el patrón, de modo que puedes empezar a aplicarlo rápidamente en tus propias aplicaciones PHP. Una nota final antes de seguir: todos los ejemplos que verás aquí se harán con PHP5, pero pueden ser fácilmente modificables para trabajar con PHP4 también. Definir una clase objetivo Para demostrar una implementación práctica de patrón de diseño "peso mosca" con PHP5, voy a empezar creando una clase objetivo. Esta clase será utilizada por un objeto flywight para mantener las instancias de esta clase limitadas a un número especificado. Como verás, cualquier intento de crear nuevas instancias de la clase dará como resultado la devolución, al código llamador, del mismo objeto. Ahora, ¿estás empezando a entender como funcionar el patrón? Seguro que sí. Habiendo explicado la lógica que planeo seguir en este caso, aquí está definición de la clase mencionada. Como puedes ver, la definición de la clase "TextInputBox" es muy fácil de entender. En pocas palabras, lo que hace esta clase es mostrar una simple caja de texto, que es útil para hacer formularios online. Ahora que has visto la definición de la anterior clase objetivo, vamos a crear otra. Esta nueva clase será para mostrar un botón de envío normal y corriente, de modo que sea posible construir un formulario de contacto simple programáticamente. La definición de esta nueva clase se puede ver a continuación, así que presta atención: En este momento, hemos creado dos clases simples que son capaces de pintar diferentes elementos de un formulario web. La cuestión que viene ahora es: ¿cómo ponerlas a trabajar juntas? Para responder a esto, abajo se puede ver un pequeño script que muestra un formulario de contacto simple usando las dos clases previas, que está formado por tres cajas de texto y el correspondiente botón de envío. Aquí está el código en cuestión: Como se ha demostrado antes, el par de clases que se han creado antes se usaron para mostrar un simple formulario de contacto que contiene tres cajas de texto, para que los usuarios puedan introducir su nombre, dirección y e-mail. Hasta aquí todo correcto,¿verdad? Ahora, planteémonos la siguiente pregunta: ¿Qué pasa si quieres hacer un generador de formularios que sólo crea tres instancias de la clase "InputTextBox" previa, sin importar las veces que intentes instanciar nuevos objetos? Bién, aquí es donde el patrón flyweight entra en escena. Es posible definir una clase factoría que sólo retorna al código llamador, tres instancias de la misma clase "InputTextBox". Esto implica que la instanciación de objetos estaría completamente equilibrada dentro de la aplicación. La cosa se está poniendo interesante,¿que no? En las siguientes lineas vamos a ver como crear la clase factoría del patrón. Como dijimos antes, será responsable de devolver tres instancias únicas de la clase “InputTextBox”. De acuerdo con los conceptos de la sección anterior, aplicar el patrón "peso mosca" es sólo cuestión de definir una factory class que será capaz de retornar al cliente sólo tres instancias de la clase "InputTextBox" que hemos definido previamente. Para responder a este requerimiento definimos una clase factoria flyweight. Obviamente devuelve tres objetos de cajas de texto al llamador. La definición de esta nueva clase es como sigue: Como puedes ver, la anterior factoría sólo suministra un método, llamado “fetchFormElement(),” el cual es responsable de crear tres instancias de la clase "TextInputBox" creada previamente. Bien, si usas esta factoría para hacer un formulario de contacto simple, siempre devolverá los mismos objetos input text, no importa cuantas veces es invocada la clase en toda la aplicación. Lógicamente, esto previene las instanciaciones innecesarias de objetos que no son realmente requeridas, aumentando el rendimiento general de cualquier aplicación. Muy bien, ¿no?. Sin embargo, una vez entiendes cómo funciona la anterior factory, hay que dar otra paso más para demostrar la funcionalidad de la clase. Por lo tanto, en la siguiente sección vamos a configurar una ejemplo práctico que nos enseñará como usar la factory class para crear un básico formulario online que sólo contiene tres cajas de texto. Viendo el patrón "peso mosca" en acción Para demostrar la funcionalidad suministrada por la factoría flyweight que hemos hecho, primero definiremos una generador de formularios genérico para hacer formularios online, y a continuación desarrollaremos un ejemplo en el que se van a poner a trabajar juntas todas las clases. Como verás en breve, aplicar el patrón de diseño "peso mosca" nos permitirá construir una fromulario de contacto básico que sólo contendrá los tres campos de entrada ya vistos. De acuerdo con la lógica seguida por el patrón, cualquier intento de crear nuevos objetos del formulario será rechazado, manteniendo equilibrada la creación de objetos. Dicho esto, aquí está la definición que corresponde a la clase generadora de formularios: Ahora échale un vistazo al siguiente ejemplo, que construye el formulario de contacto usando la factory: Como hemos visto, el formulario de ejemplo está hecho usando la funcionalidad de la factoría, cobinando con el generador de formularios. Lógicamente, este proceso es bastante fácil de seguir, y ciertamente no tiene nada de especial. Sin embargo, mira qué pasa cuando intentamos instanciar una nueva text box: En este caso el script lanza una excepción y se aborta la ejecución del programa. Ahora tenemos otra situación en la que intentamos crear dos text input que se llamen "name". En este caso, el script devuelve dos objetos idénticos: Ahora deberías tener bastante claro como trabaja el patrón peso mos
Puesto que estoy un poco pez en esto del PHP, y no me vendría mal aprender puesto que en SmallSquid usamos esta tecnología, voy a colgar o traducir de vez en cuando algún artículo que vea por ahí sobre el tema. Éste, en concreto, lo he sacado de DevShed. Así que vamos allá.
Antes de seguir, aviso a los que no quieren que le "rayen" con cosas densas. Pasad del rollo y mirar algún otro post o id directamente a los tentáculos del chipirón, que siempre hay cosas más interesantes que leer.
Introducción
Entre la considerable variedad de patrones de diseño estructural que se pueden implementar con PHP 4 (y PHP 5), hay uno en particular que merece especial atención. Es de fácil aplicación en el contexto de una aplicación web dada, y ofrece una funcionalidad remarcable cuando se usa para prevenir la instanciación innecesaria de diferentes clases.
Dejadme explicaros brevemente como funciona el patrón flyweight. Esto os dará una mejor idea de cómo y cuando se puede usar.// define 'TextInputBox' class
class TextInputBox{
private $name;
private $size;
private $maxlength;
// assign default values for properties of input box
public function __construct($name='default_name',$size=16,$maxlength=32){
if(!preg_match("/[a-zA-Z]+/",$name)){
throw new Exception('Invalid value for name property!');
}
if(!is_int($size)||$size<0||$size>32){
throw new Exception('Invalid value for size property!');
}
if(!is_int($maxlength)||$maxlength<16||$maxlength>64){
throw new Exception('Invalid value for maxlength property!');
}
$this->name=$name;
$this->size=$size;
$this->maxlength=$maxlength;
}
// get (X)HTML markup of input text box
public function getHTML(){
return '< type="text" name="">name.'"
size="'.$this->size.'" maxlength="'.$this->maxlength.'" />';
}
}// define 'SubmitButton' class
class SubmitButton{
private $name;
private $value;
public function __construct($name='default_name',$value='SendData'){
if(!preg_match("/[a-zA-Z]+/",$name)){
throw new Exception('Invalid value for name property!');
}
if(!preg_match("/[a-zA-Z]+/",$value)){
throw new Exception('Invalid argument for value property!');
}
$this->name=$name;
$this->value=$value;
}
// get (X)HTML markup of submit button
public function getHTML(){
return '< type="submit" name="">name.'" value="'.$this->value.'"/>';
}
}
try{
// instantiate input text box objects
$nameBox=new TextInputBox('name');
$addressBox=new TextInputBox('address');
$emailBox=new TextInputBox('email');
// instantiate submit button
$subButton=new SubmitButton('send');
// display form
echo '<>'."n".'Name '.$nameBox->getHTML().'
'."n".'Address '.$addressBox->getHTML().'
'."n".'Email '.$emailBox->getHTML().'
'."n".$subButton->getHTML()."n".'';
}
catch(Exception $e){
echo $e->getMessage();
exit();
}
Definir la clase factoría de "peso mosca"// define 'FlyweightFormElementFactory' class
class FlyweightFormElementFactory{
private $formElements=array();
public function __construct(){
$this->formElements['name']=NULL;
$this->formElements['address']=NULL;
$this->formElements['email']=NULL;
}
// return only three text input boxes
public function fetchFormElement($elementName){
if($elementName!='name'&&$elementName!=
'address'&&amp;amp;amp;amp;amp;amp;amp;$elementName!='email'){
throw new Exception('Invalid name for form element!');
}
if($this->formElements[$elementName]==NULL){
$this->formElements[$elementName]=new TextInputBox
($elementName);
}
return $this->formElements[$elementName];
}
}// define 'FormGenerator' class
class FormGenerator{
private $method='post';
private $action='processform.php';
private $formElements=array();
public function addFormElement(TextInputBox $formElement){
$this->formElements[]=$formElement;
}
// fetch (X)HTML markup of web form
public function displayForm(){
$html='< method="">method.'" action="'.$this->action.'">';
foreach($this->formElements as $formElement){
$html.=$formElement->getHTML().'<>';
}
$html.='< type="submit" value="Send Data">< /form>';
return $html;
}
}// example building a web form using the Flyweight design pattern
try{
// instantiate 'FlyweightFormElementFactory' object
$flyweightFormElemFactory=new FlyweightFormElementFactory();
// instantiate input text boxes
$flyweightNameBox=$flyweightFormElemFactory->fetchFormElement('name');
$flyweightAddressBox=$flyweightFormElemFactory->fetchFormElement('address');
$flyweightEmailBox=$flyweightFormElemFactory->fetchFormElement('email');
// instantiate 'FormGenerator' object
$formGenerator=new FormGenerator();
// add input text objects to form generator
$formGenerator->addFormElement($flyweightNameBox);
$formGenerator->addFormElement($flyweightAddressBox);
$formGenerator->addFormElement($flyweightEmailBox);
echo $formGenerator->displayForm();
}
catch(Exception $e){
echo $e->getMessage();
exit();
}// try instantiating a different input text box (triggers an exception)
// $flyweightNameBox1=$flyweightFormElemFactory->fetchFormElement('postalcode');// instantiate two identical 'name' input boxes
$flyweightNameBox1=$flyweightFormElemFactory->fetchFormElement('name');
$flyweightNameBox2=$flyweightFormElemFactory->fetchFormElement('name');
if($flyweightNameBox1===$flyweightNameBox2){
throw new Exception('Input text boxes objects are the same!');
}
No hay comentarios.:
Publicar un comentario