我现在正在研究装饰器模式,这里是一些示例代码(PHP):
abstract class component{
public function drawShape(){};
}
class concreteComponent extends component{
public function drawShape(){//code};
}
class decoratorComponent extends component{
private $component;
public function __construct($component){ $this->component=$component; }
public function drawShape(){
$this->component->drawShape();
}
}
class borderDecorator extends decoratorComponent{
public function drawShape(){
$this->drawBorder();
$this->component->drawShape();
}
public function setBorder(){};
public function drawBorder(){};
}
class bgColorDecorator extends decoratorComponent{
public function drawShape(){
$this->drawBgColor();
$this->component->drawShape();
}
public function setbgColor(){};
public function drawBgColor(){};
}
好的,现在:
$test=new concreteComponent();
$border=new borderDecorator($test);
$border->setBorder(10);
$bgColor= new bgColorDecorator($border);
$bgColor->setBgColor(#000);
现在我有一个装饰有#000 bg颜色和10(某些单位)边框的组件。
用
$bgColor->drawShape();
表示drawBgColor
+ drawBorder
+ drawShape
并且没错,但是:
如何修改或删除边框??
$bgColor-> ???
bgColor类无法直接访问边框方法...
由于
答案 0 :(得分:0)
根据我的理解,你已经将一个bgColorDecorator实例与你无法设置/删除边框的方式链接了你的装饰器。
你应该做的是改变构造的顺序并由borderDecorator部分完成:
$test=new concreteComponent();
$bgColor= new bgColorDecorator($test); // pass test to bgcolor
$bgColor->setBgColor(#000);
$border=new borderDecorator($bgColor); // pass bgcolor to border
$border->setBorder(10);
// You can now set/remove border on $border
// and of course : $border->drawShape();
您的任务似乎是渲染对象,因此正确的绘制顺序应该需要更改drawShape方法以保持顺序背景/形状/边框
$this->drawBgColor();
$this->component->drawShape();
// will become a post-action
$this->component->drawShape();
$this->drawBgColor();
现在问题是你因为同样的原因而无法动态设置backgroundcolor 。所以另一个解决方案可能是修改你的decoratorComponent接口以包含你需要的东西并在decoratorComponent子类中实现它。
编辑双边框案例:
将两个borderDecorator链接到一个Component
$cmp = new concreteComponent();
$bDecrtor1 = new borderDecorator($cmp); // 1st border decorator on cmp
$bDecrtor1 ->setBorder(10);
$bDecrtor2=new borderDecorator($bDecrtor1); // 2nd border decorator on 1st one
$bDecrtor2->setBorder(20);
// $bDecrtor2->drawShape();
// You can then use bDecrtor1 or bDecrtor2 to (re)set the border properties
// You can use bDecrtor2 to chain other decorators...
答案 1 :(得分:0)
你可以做的是实现名为magic method的__call()
(一个包罗万象的方法),尝试将任何不存在的方法委托给包裹的component
:
class decoratorComponent extends component{
private $component;
/* ... */
public function __call( $name, $arguments ) {
return call_user_func_array( array( $this->component, $name ), $arguments );
}
}
您必须建立安全措施,以便了解您尝试调用的方法最终不存在于任何组件中的情况。
但是,您可能还应该评估是否甚至需要在之后调用装饰器方法,然后将它们包装在另一个装饰器中。