sourcemaking source patterns making example php oop decorator

source - ¿Cómo implementar un decorador en PHP?



design patterns (5)

Eso es bastante fácil, especialmente en un lenguaje de tipado dinámico como PHP:

class Text { protected $string; /** * @param string $string */ public function __construct($string) { $this->string = $string; } public function __toString() { return $this->string; } } class LeetText { protected $text; /** * @param Text $text A Text object. */ public function __construct($text) { $this->text = $text; } public function __toString() { return strtr($this->text->__toString(), ''eilto'', ''31170''); } } $text = new LeetText(new Text(''Hello world'')); echo $text; // H3110 w0r1d

Es posible que desee echar un vistazo al artículo de wikipedia , también.

Supongamos que hay una clase llamada " Class_A ", tiene una función miembro llamada " func ".

Quiero que el " func " haga un trabajo extra envolviendo Class_A en una clase de decorador.

$worker = new Decorator(new Original());

¿Alguien puede dar un ejemplo? Nunca he usado OO con PHP.

¿La siguiente versión es correcta?

class Decorator { protected $jobs2do; public function __construct($string) { $this->jobs2do[] = $this->do; } public function do() { // ... } }

El código anterior tiene la intención de poner un poco de trabajo adicional a una matriz.


Ninguna de estas respuestas implementa Decorator correctamente y con elegancia. La respuesta de mrmonkington se acerca, pero no es necesario utilizar el reflejo para representar el patrón Decorator en PHP. En otro hilo, @Gordon muestra cómo usar un decorador para registrar la actividad de SOAP . Así es como lo hace:

class SoapClientLogger { protected $soapClient; // this is standard. Use your constuctor to set up a reference to the decorated object. public function __construct(SoapClient $client) { $this->soapClient = $client; } ... overridden and / or new methods here ... // route all other method calls directly to soapClient public function __call($method, $args) { // you could also add method_exists check here return call_user_func_array(array($this->soapClient, $method), $args); } }

Y es una ligera modificación en la que puede pasar la funcionalidad deseada al constructor:

class Decorator { private $o; public function __construct($object, $function_name, $function) { $this->o = $object; $this->$function_name = $function; } public function __call($method, $args) { if (!method_exists($this->o, $method)) { throw new Exception("Undefined method $method attempt in the Url class here."); } return call_user_func_array(array($this->o, $method), $args); } }


Quería usar la decoración para alentar a los colegas a usar el almacenamiento en caché más, e inspirado por la agradable sintaxis de Python experimentada con la reflexión de PHP para falsificar esta característica del lenguaje (y tengo que enfatizar ''falso''). Fue un enfoque útil. Aquí hay un ejemplo:

class MrClass { /** * decoratorname-paramname: 50 * decoratorname-paramname2: 30 */ public function a_method( $args ) { // do some stuff } } class DecoratorClass { public function __construct( $obj ) { $this->obj = $obj; $this->refl = new ReflectionClass( $obj ); } public function __call( $name, $args ) { $method = $this->refl->getMethod( $name ); // get method''s doccomment $com = trim( $method->getDocComment() ); // extract decorator params from $com $ret = call_user_func_array( array( $this->obj, $name), $args ); // perhaps modify $ret based on things found in $com return $ret; }

Mejores ejemplos con ejemplos de almacenamiento en caché aquí: https://github.com/mrmonkington/EggCup/


Sugiero que también cree una interfaz unificada (o incluso una clase base abstracta) para los decoradores y los objetos que desee decorar.

Para continuar con el ejemplo anterior, podría tener algo como:

interface IDecoratedText { public function __toString(); }

Luego, por supuesto, modifique Text y LeetText para implementar la interfaz.

class Text implements IDecoratedText { ...//same implementation as above } class LeetText implements IDecoratedText { protected $text; public function __construct(IDecoratedText $text) { $this->text = $text; } public function __toString() { return str_replace(array(''e'', ''i'', ''l'', ''t'', ''o''), array(3, 1, 1, 7, 0), $this->text->toString()); } }

¿Por qué usar una interfaz?

Porque entonces puede agregar tantos decoradores como desee y tener la seguridad de que cada decorador (u objeto a decorar) tendrá todas las funciones requeridas.


Una característica clave y única del Decorador es que una clase abstracta se extiende a otra. El participante Decorador es a la vez envoltorio y amplía al participante del componente.

<?php abstract class Decorator extends IComponent { //public function getDescription() { } } ?>

Creo que este es el único patrón en el que sucede esto en el catálogo de Gang of Four. Decorator hace que sea fácil agregar propiedades a un objeto sin cambiar el objeto. Para un ejemplo simple, preciso y claro, vea:

http://www.php5dp.com/php-decorator-design-pattern-accessorizing-your-classes/#more-32