Foros del Web » Programando para Internet » PHP » Frameworks y PHP orientado a objetos »

Decorator Pattern in PHP5

Estas en el tema de Decorator Pattern in PHP5 en el foro de Frameworks y PHP orientado a objetos en Foros del Web. Hola, De ocioso he estado analizando un par de patrones de diseño y me he topado con un problema en un ejemplo del Decorator Pattern. ...
  #1 (permalink)  
Antiguo 14/02/2007, 11:14
 
Fecha de Ingreso: noviembre-2003
Mensajes: 798
Antigüedad: 20 años, 5 meses
Puntos: 8
Decorator Pattern in PHP5

Hola,

De ocioso he estado analizando un par de patrones de diseño y me he topado con un problema en un ejemplo del Decorator Pattern.

El problema es que no funciona como debería, en las subclasses de la clase decorator "String_Formatter" solo ejecuta con exito la 1º, osea String_Formatter_Uppercase, en las restantes hijas el metodo getString del padre obtiene un nulo.

La salida en el metodo output debiese ser "PATTERNS FOR PHP"

Aqui dejo el ejemplo haber si alguien más experimentado que yo me ayuda a encontrar la correcta solución.

La fuente del ejemplo lo he sacado de patternsforphp.com.

Código PHP:
<?php

class String_Writer {
 
    private 
$path '';
    private 
$string '';
 
    public function 
__construct($path) {
        
$this->path $path;
    }
 
    public function 
setString($string) {
        
$this->string $string;
    }
 
    public function 
getString() {
        return 
$this->string;
    }
 
    public function 
getPath() {
        return 
$this->path;
    }
 
    public function 
store() {
        
// we assume one string per line
        
if(!file_put_contents($this->path$this->string PHP_EOLFILE_APPEND))
        {
            throw new 
Exception('Error writing to specified path');
        }
    }
    
}

class 
String_Formatter {
 
    private 
$string '';
 
    public function 
__construct(String_Writer $writer) {
        
$this->string $writer->getString();
    }
 
    public function 
getString() {
        return 
$this->string;
    }
 
    public function 
setString($string) {
        
$this->string $string;
    }
 
    public function 
output() {
        return 
$this->string;
    }
 
}

interface 
iString_Formatter {
 
    public function 
format();
 
}
 
class 
String_Formatter_Uppercase extends String_Formatter implements iString_Formatter {
 
    private 
$stringFormatter;
 
    public function 
__construct(String_Formatter $stringFormatter) {
        
$this->stringFormatter $stringFormatter;
        
    }
 
    public function 
format() {
        
$this->stringFormatter->setString(
            
strtoupper($this->stringFormatter->getString())
        );
        
    }
 
}
 
class 
String_Formatter_Reverse extends String_Formatter implements iString_Formatter {
 
    private 
$stringFormatter;
 
    public function 
__construct(String_Formatter $stringFormatter) {
        
$this->stringFormatter $stringFormatter;
        
//print $this->stringFormatter->getString().'X';
    
}
 
    public function 
format() {
        
$this->stringFormatter->setString(
            
strrev($this->stringFormatter->getString())
        );
        
        
    }
 
}
 
class 
String_Formatter_Escape extends String_Formatter implements iString_Formatter {
 
    private 
$stringFormatter;
 
    public function 
__construct(String_Formatter $stringFormatter) {
        
$this->stringFormatter $stringFormatter;
        
    }
 
    public function 
format() {
        
$this->stringFormatter->setString(
            
htmlentities($this->stringFormatter->getString(), ENT_QUOTES'UTF-8')
        );
    }
 
}

/*
require('String_Writer.php');
require('String_Formatter.php');
require('iString_Formatter.php');
require('String_Formatter_Uppercase.php');
require('String_Formatter_Reverse.php');
require('String_Formatter_Escape.php');
*/

$string 'php rof snrettap';
$path './stringlog';
 
/*
Create a new String_Writer object
*/

$stringWriter = new String_Writer($path);
$stringWriter->setString($string);
 
/*
Store the string to a file
*/
$stringWriter->store();
 
/*
Instantiate a String_Formatter object to control output
*/
$stringFormatter = new String_Formatter($stringWriter);
 
/*
Instantiate specific String_Formatters. Pass in String_Formatter object
as parameter to first Formatter. Pass new Formatter into third, etc.
This chained set of parameters links all the Formatters to the same string.
*/
$stringUppercase = new String_Formatter_Uppercase($stringFormatter);
$stringReverse = new String_Formatter_Reverse($stringUppercase);
$stringEscape = new String_Formatter_Escape($stringReverse);
 
/*
Perform the formatting, call format() method of each required Formatting option
*/
$stringUppercase->format();
$stringReverse->format();
$stringEscape->format();
 
/*
Return the results for output
*/

print $stringFormatter->output();
//$output = $stringFormatter->output();
 
/*
Exit the script while printing the resulting formatted string (which is also
stored in our log file in original form)
*/
//exit($output); // PATTERNS FOR PHP (reversed, uppercased and escaped!) 
?>
Gracias y saludos.
  #2 (permalink)  
Antiguo 14/02/2007, 13:44
 
Fecha de Ingreso: noviembre-2003
Mensajes: 798
Antigüedad: 20 años, 5 meses
Puntos: 8
Re: Decorator Pattern in PHP5 [Solucionado]

Solucionado!!!

Si no me equivoco y haber si alguien me lo confirma, hay que remplazar lo siguiente:

Código PHP:
$stringUppercase = new String_Formatter_Uppercase($stringFormatter);
$stringReverse = new String_Formatter_Reverse($stringUppercase);
$stringEscape = new String_Formatter_Escape($stringReverse); 
por:

Código PHP:
$stringUppercase = new String_Formatter_Uppercase($stringFormatter);
$stringReverse = new String_Formatter_Reverse($stringFormatter);
$stringEscape = new String_Formatter_Escape($stringFormatter); 
  #3 (permalink)  
Antiguo 14/02/2007, 16:02
Avatar de Felippe  
Fecha de Ingreso: octubre-2006
Mensajes: 54
Antigüedad: 17 años, 6 meses
Puntos: 0
Re: Decorator Pattern in PHP5

Hola zsamer:

Me intereso tu ejemplo, y tienes razon en la corrección que hiciste, debia pasarse el objeto '$stringFormatter' a los formatters.

Si me permites una observación o una variante a este ejemplo, podría ser:

- Hacer que la clase 'String_Formatter' extienda de la clase 'String_Writer'.
- Definir la clase 'String_Formatter' como abstracta, definiendo el método 'format' como método abstracto.
- Hacer que las clases formatters, extiendan solamente de 'String_Formatter', implementando el método 'format' a su modo.

Te muestro un ejemplo de lo que digo solamente para la clase 'String_Formatter_Uppercase':
Código:
abstract class String_Formatter extends String_Writer{
 
   //private $string = '';
 
   /*
    public function __construct(String_Writer $writer) {
        $this->string = $writer->getString();
    }
	 
    public function getString() {
        return $this->string;
    }
 
    public function setString($string) {
        $this->string = $string;
    }
 
    public function output() {
        return $this->string;
    }
   */
   public abstract function format();
}

/** Clase formatter UpperCase */
class String_Formatter_Uppercase extends String_Formatter /*implements iString_Formatter*/ {
 
    //private $stringFormatter;
 
    /*
    public function __construct(String_Formatter $stringFormatter) {
        $this->stringFormatter = $stringFormatter;
    }
   */
 
    public function __construct($path) {
        parent::__construct($path);
    }
	
    public function format() {
		$this->setString( strtoupper($this->getString()) );
    }
 
}

/** Pagina index.php */
require('String_Writer.class.php');
require('String_Formatter.class.php');
require('String_Formatter_Uppercase.class.php');
 
$string = 'php rof snrettap';
$path = 'h:/xampp/htdocs/decorador/prueba.txt';

/** Definir la clase formatter */
$stringUppercase = new String_Formatter_Uppercase($path);
/** Pasar el valor */
$stringUppercase->setString($string);
/** Darle el formato */
$stringUppercase->format();
/** Almacenarlo */
$stringUppercase->store();
/** Mostrar resultado */
print $stringUppercase->getString();
Deje comentado el código que puede ahorrarse y las negritas muestran los cambios.

Ademas, en la pagina index.php (así le llame a la pagina de prueba) evitamos hacer demasiadas instanciaciones (tal vez innecesarias, al menos yo la veo mas limpia).

Esto lo hice al ver que en el ejemplo original, define una estructura no aprovechada, al recibir como parámetro un objeto de tipo 'String_Formatter' y al mismo tiempo hereda de él (eso me confundio un poco al principio).

Si hay alguna observación, estoy abierto a críticas o sugerencias.

Un saludo, un gusto tratar este tema.
  #4 (permalink)  
Antiguo 14/02/2007, 20:45
 
Fecha de Ingreso: noviembre-2003
Mensajes: 798
Antigüedad: 20 años, 5 meses
Puntos: 8
Re: Decorator Pattern in PHP5

Me parece que la idea del Decorate Patterns es evitar la herarquia de la clase base, osea de String_Writer, ya que unos de los principios fundamentales de este patron es no tocar nada absolutamente nada de la clase base y entregar todo el poder a la clase Decorator.
  #5 (permalink)  
Antiguo 15/02/2007, 07:51
Avatar de Felippe  
Fecha de Ingreso: octubre-2006
Mensajes: 54
Antigüedad: 17 años, 6 meses
Puntos: 0
Re: Decorator Pattern in PHP5

Ups ! , pasé por alto la independencia entre el Decorador y el Decorado, tienes razón.

Tal vez lo apropiado sea que las clases formatters, reciban como parámetro el objeto String_Writer, entonces la clase String_Formatter quedaría así:

Código:
abstract class String_Formatter{
 
    public abstract function format(String_Writer obj);
}
Y cada formatter, luego de hacer su trabajo como corresponda:
Código:
class String_Formatter_Uppercase extends String_Formatter {
 
	public function __construct() {
    }
	
    public function format(String_Writer $obj) {
		$obj->setString( strtoupper($obj->getString()) );
    }
}
De esa manera la pagina de prueba quedaría reducida a esto:
Código:
$string = 'php rof snrettap';
$path = 'prueba.txt';

/** Mantenemos el codigo original del sistema anterior */
$stringWriter = new String_Writer($path);
$stringWriter->setString($string);

/** Y le aplicamos el formato */
$stringUppercase = new String_Formatter_Uppercase();
$stringUppercase->format($stringWriter);

/** El objeto $stringWriter puede continuar con su vida..... */
$stringWriter->store();
print $stringWriter->getString();
Es que aún no me convence la estructura del ejemplo original (a excepción del interface que es lo que le agregaría a mi variante)
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 12:54.