Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 装饰图案问题_Php_Oop_Design Patterns_Dependency Injection_Decorator - Fatal编程技术网

Php 装饰图案问题

Php 装饰图案问题,php,oop,design-patterns,dependency-injection,decorator,Php,Oop,Design Patterns,Dependency Injection,Decorator,我正在使用装饰器模式向输出流(控制台)添加样式和选项 它是一个控制台应用程序,可以为命令行输出添加颜色。这个 装饰师添加颜色。客户端类中的条件是 如果发生错误则用红色文本进行装饰,如果未发生错误则用绿色文本进行装饰。颜色 因此,decorator具有可选调用,只有ClientClass 我可以知道 *OP对其中一个答案的评论副本 我的问题是:我正在通过构造函数将我的装饰器传递给一个类。但是修饰对象需要调用两个不在基类中的方法,即被修饰的方法 这不好吗?我不应该只调用那些在所有修饰类中都可用的方法

我正在使用装饰器模式向输出流(控制台)添加样式和选项

它是一个控制台应用程序,可以为命令行输出添加颜色。这个 装饰师添加颜色。客户端类中的条件是 如果发生错误则用红色文本进行装饰,如果未发生错误则用绿色文本进行装饰。颜色 因此,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()中实现这些调用
方法,如我所说。但是调用是可选的,并且基于一个只有客户知道的条件,这就是我试图得到的。我已将问题再次更新为