2

デコレータパターンを使用して、出力ストリーム(コンソール)にスタイルとオプションを追加しています。

これは、コマンドライン出力に色を追加するコンソールアプリです。デコレータが色を追加します。ClientClassの条件は、 エラーが発生した場合は赤いテキストで装飾し、エラーが発生しなかった場合は緑色のテキストで装飾することです。したがって、カラーデコレータには、ClientClassだけ が知ることができるオプションの呼び出しがあります。

*回答の1つに対するOPのコメントのコピー

私が抱えている問題はこれです:コンストラクターを介してデコレーターをクラスに渡します。しかし、装飾されたオブジェクトは、基本クラスにない2つのメソッド、つまり装飾されているメソッドを呼び出す必要があります。

これは悪いですか?すべての装飾されたクラスで利用可能なメソッドのみを呼び出すべきではありませんか?

例として:

<?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を拡張するすべてのクラスで使用可能な抽象メソッドdoYourThing()を呼び出す前に、decoratorFunctionAとdecoratorFunctionB(デコレータクラスでのみ使用可能)を呼び出す必要があります。これは間違っていると感じます。

デコレータの実装は正しいと思いますが、今はこの他の問題で立ち往生しています

どうすればこれを解決できますか?

クライアントクラスは、decoratorFunctionA()とdecoratorFunctionB()の両方を呼び出す必要がない場合があります。必要なのは、1つだけか、まったくないため、doYourThing呼び出しでこれらを自動的に呼び出すことはできません。

MyAceBaseClassDecoratorAのインターフェイスを使用することも可能ですが、そもそもデコレータを使用するという目的に反しています。

4

3 に答える 3

1

期待しているインターフェースで指定されていないメソッドを呼び出すことはできません: MyAceBaseClass(@ctraheyが指摘したように)。

また、正しく読めば、混乱しているようです。この場合、誰が誰を飾っていますか?

デコレータパターンの目的がサブクラス化せずに(つまり、オブジェクトが「である」とは言わずに)既存のオブジェクトに機能を追加することである場合、デコレータは装飾されたオブジェクトで保護されたプロパティを持っている必要があります。ClientClassあなたが呼んだものを飾っているのはあなたのようですMyAceBaseClassDecoratorA

IMO、それはこの線に沿ったものでなければなりません:

// 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->decoratorFunctionA();たり$this->aceObject->decoratorFunctionB();、デコレータの外に出たりすることはありませんClientClass

doYourThing()代わりに、メソッドを呼び出す前に、装飾されたオブジェクトにメソッドに注入された機能を提供する必要があります$ClientClass->aceObject->doYourThing()

エラーがある場合は、で装飾します。RedTextDecoratorすべてがうまくいった場合は、代わりに、で装飾しますGreenTextDecorator

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;
}
于 2012-08-25T18:15:05.127 に答える
0

ええ、コンストラクターがMyAceBaseClassを受け取る場合、その子孫クラスの1つで宣言されているメソッドをコンストラクターで呼び出さないでください。$ aceObjectクラスが常にデコレータである場合は、そのインターフェイスを作成し、インターフェイスで宣言されているメソッドのみを呼び出します。これがインターフェイスの目的です。1つのクリーンなメソッドに「煮詰め」、デコレータに呼び出す特定のメソッドを知る責任を委任すると役立つ場合があります。

ただし、デコレータについて知っている主題よりも、デコレータが主題について知っている方がよいと言うかもしれません。オブジェクトとそのデコレータとの関係は、可能な限り緩く結合する必要があります。できれば、デコレーションできることを単純に知っている必要があります(つまり、「デコレータ可能な」インターフェイスや、関心のあるデコレータが観察できる観察メカニズムの実装などの類似したものを実装します)。 。ただし、デコレータその主題について知っていることは、インターフェイスを介してのみ行う必要があります。

于 2012-08-25T17:32:29.037 に答える
0

簡単にしたい場合は、条件(色を追加するかどうか)に基づいて、doYourThingメソッド内でdecoratorFunctionA()とdecoratorFunctionB()を使用できます。このようにして、契約は同じままになり、必要な機能を取得できます。

より明確にしたい場合は、2つの異なるデコレータを使用できます。

詳細については、これを参照できます。

http://en.wikipedia.org/wiki/Decorator_pattern

于 2012-08-27T07:01:45.363 に答える