Предположим, что существует класс, называемый « Class_A
», он имеет функцию-член, называемую « func
».
Я хочу, чтобы « func
» выполнял некоторую дополнительную работу, обернув Class_A
классом декоратора.
$worker = new Decorator(new Original());
Может ли кто-нибудь привести пример? Я никогда не использовал OO с PHP.
Правильно ли следующая версия?
class Decorator { protected $jobs2do; public function __construct($string) { $this->jobs2do[] = $this->do; } public function do() { // ... } }
Вышеупомянутый код намеревается добавить некоторую дополнительную работу в массив.
Я бы предположил, что вы также создаете унифицированный интерфейс (или даже абстрактный базовый класс) для декораторов и объектов, которые вы хотите украсить.
Чтобы продолжить приведенный выше пример, вы можете иметь что-то вроде:
interface IDecoratedText { public function __toString(); }
Затем, конечно, измените как Text
и LeetText
чтобы реализовать интерфейс.
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()); } }
Зачем использовать интерфейс?
Потому что тогда вы можете добавить столько декораторов, сколько хотите, и быть уверенным, что каждый декоратор (или объект, который будет оформлен) будет обладать всеми необходимыми функциями.
Это довольно легко, особенно на динамически типизированном языке, таком как 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
Вы можете также взглянуть на статью в Википедии .
Ни один из этих ответов не выполняет Decorator
правильно и элегантно. Ответ mrmonkington близок, но вам не нужно использовать отражение, чтобы ввести шаблон Decorator
в PHP. В другом потоке @Gordon показывает, как использовать декоратор для регистрации активности SOAP . Вот как он это делает:
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); } }
И он – небольшая модификация, где вы можете передать желаемую функциональность конструктору:
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); } }
Я хотел использовать украшение, чтобы побудить коллег использовать кеширование больше, и вдохновил хороший синтаксис Python, экспериментированный с рефлексией PHP, чтобы подделать эту языковую функцию (и я должен подчеркнуть «подделку»). Это был полезный подход. Вот пример:
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; }
Лучшие примеры с примерами кеширования: https://github.com/mrmonkington/EggCup/
Ключевой и уникальной особенностью Decorator является то, что один абстрактный класс расширяет другой. Участник Decorator является оберткой и расширяет компонент Component.
<?php abstract class Decorator extends IComponent { //public function getDescription() { } } ?>
Я считаю, что это единственный пример, когда это происходит в каталоге «Банда четырех». Декоратор позволяет легко добавлять свойства к объекту без изменения объекта. Для простого, точного и четкого примера см .:
http://www.php5dp.com/php-decorator-design-pattern-accessorizing-your-classes/#more-32