Php 装饰图案问题
我正在使用装饰器模式向输出流(控制台)添加样式和选项 它是一个控制台应用程序,可以为命令行输出添加颜色。这个 装饰师添加颜色。客户端类中的条件是 如果发生错误则用红色文本进行装饰,如果未发生错误则用绿色文本进行装饰。颜色 因此,decorator具有可选调用,只有ClientClass 我可以知道 *OP对其中一个答案的评论副本 我的问题是:我正在通过构造函数将我的装饰器传递给一个类。但是修饰对象需要调用两个不在基类中的方法,即被修饰的方法 这不好吗?我不应该只调用那些在所有修饰类中都可用的方法吗 例如:Php 装饰图案问题,php,oop,design-patterns,dependency-injection,decorator,Php,Oop,Design Patterns,Dependency Injection,Decorator,我正在使用装饰器模式向输出流(控制台)添加样式和选项 它是一个控制台应用程序,可以为命令行输出添加颜色。这个 装饰师添加颜色。客户端类中的条件是 如果发生错误则用红色文本进行装饰,如果未发生错误则用绿色文本进行装饰。颜色 因此,decorator具有可选调用,只有ClientClass 我可以知道 *OP对其中一个答案的评论副本 我的问题是:我正在通过构造函数将我的装饰器传递给一个类。但是修饰对象需要调用两个不在基类中的方法,即被修饰的方法 这不好吗?我不应该只调用那些在所有修饰类中都可用的方法
<?php
abstract class MyAceBaseClass
{
abstract function doYourThing();
}
class MyAceBaseClassDecoratorA extends MyAceBaseClass
{
protected $aceBaseClass;
protected $amount = 0;
public function __construct($aceBaseClass)
{
$this->_aceBaseClass = $aceBaseClass;
}
public function doYourThing()
{
$result = $aceBaseClass + $this->amount;
return $result;
}
public function decoratorFunctionA()
{
$this->amount = 10;
}
public function decoratorFunctionB()
{
//----
}
}
class ClientClass
{
private $aceObject;
public function __construct(MyAceBaseClass $aceObject)
{
$this->aceObject = $aceObject;
}
public function run()
{
if ($someCondition) {
$this->aceObject->decoratorFunctionA();
$this->aceObject->decoratorFunctionB();
}
$result = $this->aceObject->doYourThing();
echo $result;
}
}
是的,如果您的构造函数采用MyAceBaseClass,它就不应该调用在其子类中声明的方法。如果$aceObject类始终是一个decorator,那么为它创建一个接口,只调用接口中声明的方法,这就是接口的用途。将其“归结”为一个干净的方法是有帮助的,并将知道要调用哪些特定方法的责任委托给装饰师
然而,我可能会提到,我更喜欢我的装饰师了解他们的主题,而不是主题了解它的装饰师。一个对象与它的装饰器的关系应该尽可能松散地耦合,希望它只知道它可以被装饰(即实现一个“装饰”接口或类似的东西,比如实现一个感兴趣的装饰器可以观察的观察机制)。然而,装饰者对其主题的了解应该完全通过接口。您不能调用未由您期望的接口指定的方法:MyAceBaseClass
(正如@ctrahey指出的)
而且,如果我读对了,你似乎把事情搞混了在这种情况下,谁在装饰谁?
如果装饰器模式的目的是向现有对象添加功能而不进行子类化(换句话说,不说对象“是”),装饰器必须具有装饰对象的受保护属性。似乎是你的ClientClass
在装饰你所谓的MyAceBaseClassDecoratorA
在国际海事组织,应该是这样的:
// Concrete object
class MyObject implements MyObjectInterface {
public function doSomething() {
return 1;
}
}
// Your abstract decorator
abstract class MyObjectDecorator implements MyObjectInterface {
protected $myObject;
public function __construct(MyObjectInterface $object) {
$this->myObject = $object;
}
public function doSomething() {
return $this->myObject->doSomething();
}
}
// Your concrete decorator
class MyConcreteObjectDecorator extends MyObjectDecorator {
public function doSomething() {
$value = $this->myObject->doSomething();
return $value + 10;
}
}
编辑:
至于你在评论中的解释,以下是你应该做的:
class ClientClass {
// ...
public function run() {
$this->aceObject->doYourThing(); // and that's all
}
// ...
}
因此,您不会调用$this->aceObject->decoratorfuncta()
或$this->aceObject->decoratorFunctionB()代码>在装饰程序之外,就像您在ClientClass
中所做的那样
相反,在调用$ClientClass->aceObject->doYourThing()
方法之前,应该为修饰对象提供注入doYourThing()方法的功能
如果出现错误,那么您将使用redtextdecommer
装饰它,如果一切顺利,那么您将使用greentextdecommer
装饰它
public function run()
{
if ($error) {
$this->aceObject = new RedTextDecorator($this->aceObject);
} elseif($success) {
$this->aceObject = new GreenTextDecorator($this->aceObject);
}
$result = $this->aceObject->doYourThing();
echo $result;
}
如果您想让它变得简单,您可以根据条件(无论是否要添加颜色)在doYourThing方法中使用decoratorfunction()和decoratorFunctionB()。这样,您的合同将保持不变,您可以获得所需的功能
如果你想让它更清楚,那么也许你可以使用两种不同的装饰
有关更多详细信息,请参阅:
谢谢-is知道这是一个问题,因为调用这些方法感觉不对。你能看到一个潜在的解决方案吗?创建接口iMyAceBaseClassDecoratorA是一个解决方案吗?但问题是,如果我在不了解你的领域的情况下介绍另一个decorator,很难说什么是最好的。例如,如果您的ClientClass知道$aceObject将是一个decorator,那么我会说,创建一个MyAceBaseClassDecoratorA
实现的decorator接口(理想情况下只有一个方法),并将该接口用于构造函数中的类型强制,并且只从ClientClass内部调用该方法(请注意,MyAceBaseClassDecoratorA
可以自己调用更多方法)。除了基类之外,每个decorator都有自己可以做的特定事情。因此,也许我误用了decorator,另一种模式在这里是最好的。我正在学习oop,很难找到正确的模式:(模式在良好组合时最有效。例如,decorator模式与某种一对多委托模式(如复合模式或观察者模式)相比更有效;这取决于您的风格/偏好。无论哪种方式,都是一对多,或者您说“我有一个decorator”(虽然您使用的是复合模式,让该模式知道如何触发其余事件)“或“我有一个事件,但许多观察家可能想对此做些什么”谢谢Keyne。我确实按照您的描述实现了它,但出于某种原因,我将其从示例中排除了。对不起,我已经更新了我的问题以向您展示。您可以看到结果取决于正在调用的修饰函数-最终从客户机类作为可选的,即客户机可能不需要添加tenI。我仍然感到困惑:,但是装饰对象需要调用基类中不存在的两个方法,这就是为什么需要在具体的装饰器doYourThing()中实现这些调用
方法,如我所说。但是调用是可选的,并且基于一个只有客户知道的条件,这就是我试图得到的。我已将问题再次更新为