可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Suppose there is a class called "Class_A
", it has a member function called "func
".
I want the "func
" to do some extra work by wrapping Class_A
in a decorator class.
$worker = new Decorator(new Original());
Can someone give an example? I've never used OO with PHP.
Is the following version right?
class Decorator
{
protected $jobs2do;
public function __construct($string) {
$this->jobs2do[] = $this->do;
}
public function do() {
// ...
}
}
The above code intends to put some extra work to a array.
回答1:
I would suggest that you also create a unified interface (or even an abstract base class) for the decorators and the objects you want decorated.
To continue the above example provided you could have something like:
interface IDecoratedText
{
public function __toString();
}
Then of course modify both Text
and LeetText
to implement the interface.
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());
}
}
Why use an interface?
Because then you can add as many decorators as you like and be assured that each decorator (or object to be decorated) will have all the required functionality.
回答2:
That is pretty easy, especially in a dynamically typed language like 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
You may want to have a look at the wikipedia article, too.
回答3:
None of these answers implements Decorator
properly and elegantly. mrmonkington's answer comes close, but you don't need to use reflection to enact the Decorator
pattern in PHP. In another thread, @Gordon shows how to use a decorator for logging SOAP activity. Here's how he does it:
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);
}
}
And he's a slight modification where you can pass the desired functionality to the 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);
}
}
回答4:
I wanted to use decoration to encourage colleagues to use caching more, and inspired by the nice Python syntax experimented with PHP reflection to fake this language feature (and I have to stress 'fake'). It was a useful approach. Here's an example:
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;
}
Better examples with caching examples here: https://github.com/mrmonkington/EggCup/
回答5:
A key and unique feature of the Decorator is that one abstract class extends another. The Decorator participant is both a wrapper for and extends the Component participant.
<?php
abstract class Decorator extends IComponent
{
//public function getDescription() { }
}
?>
I believe that this is the only pattern where this happens in the Gang of Four catalog. The Decorator makes it easy to add properties to an object without changing the object. For a simple, accurate and clear example see:
http://www.php5dp.com/php-decorator-design-pattern-accessorizing-your-classes/#more-32