我们在使用面向对象的日常开发过程中,或许会碰见需要对某个方法或者某个对象,添加新的行为。然而常见的做法是,写一个子类继承需要改写的类,然后去重新实现类的方法。
但是装饰器模式(Decorator),可以动态地添加修改类的功能,在使用装饰器模式,仅需在运行时添加一个装饰器对象既可实现,相对与生成子类更加的灵活。
在我们需要改写一个类的时候通常的做法是采用继承的方式来重新方法,如下代码
/* * 比如我们需要改写一串字符串的样式,采用继承的写法。 */ class Canvas { function draw($width = 20, $height = 10) { for($i = 0; $i < $height; $i++) { for($j = 0; $j < $width; $j++) { echo '*'; } echo '
'; } } } class Canvas2 extends Canvas { function draw($width = 20, $height = 10) { echo ""; parent::draw($width, $height); echo ""; } } $Canvas2 = new Canvas2(); $Canvas2->draw();
对于上面的这种写法,假如我们需要多增加一个一种样式就需要多一个继承。接下来使用装饰器模式(Decorator)就会方便很多。
/* * 首先声明一个装饰器的接口 */ interface DrawDecorator { function beforeDraw(); function afterDraw(); }
接下来再分别添加两个装饰类,来继承接口,实现接口中的方法
/* * 颜色装饰 */ class ColorDrawDecorator implements DrawDecorator { protected $color; function __construct($color = 'red') { $this->color = $color; } function beforeDraw() { echo "color};'>"; } function afterDraw() { echo ""; } } /* * 字体大小装饰 */ class SizeDrawDecorator implements DrawDecorator { protected $size; function __construct($size = '14px') { $this->size = $size; } function beforeDraw() { echo "size};'>"; } function afterDraw() { echo ""; } }
接下来就是使用我们前面所创建的装饰类
/* * 创建一个画布类 */ class Canvas { protected $decorators = array(); //用来存放装饰的数组 function draw($width = 20, $height = 10) { $this->beforeDraw(); for($i = 0; $i < $height; $i++) { for($j = 0; $j < $width; $j++) { echo '*'; } echo '
'; } $this->afterDraw(); } //添加装饰器的方法 function addDecorator(DrawDecorator $decorator) { $this->decorators[] = $decorator; } function beforeDraw() { foreach($this->decorators as $decorator) { $decorator->beforeDraw(); } } function afterDraw() { $decorators = array_reverse($this->decorators); foreach($decorators as $decorator) { $decorator->afterDraw(); } } } $Canvas = new Canvas(); $Canvas->addDecorator(new ColorDrawDecorator('red')); $Canvas->addDecorator(new SizeDrawDecorator('9px')); $Canvas->draw(20, 10);