1

デコレータを再利用できますか?

クライアントの参照を持つエンティティを装飾する必要があります。このデコレーターは、 getClientClientDecoratorの呼び出しでデータベース上のクライアントを取得します(装飾される前に、このメソッドは clientId を返し、装飾された後、Clientのインスタンスを返します)。

わかりましたが、同じデコレータで装飾できるエンティティが他にもいくつかありquestionsますschedules。クライアントの参照を持っています。

ちなみに、questionscheduleで飾れClientDecoratorます。

しかし、私も持っていQuestionDecoratorます。Answerこの男は、などを飾ります。

この抽象化を行うにはどうすればよいので、いつでもデコレータを再利用できますか?

ClientDecorable、インターフェイスを作成しようとしましQuestionDecorableたが、進展がありません。

4

2 に答える 2

0

それは本当に難しい問題です。私は解決策を見つけることができましたが、それは一種のMcGiverスタイルです... PHP 5.4+で動作します(はい、特性)。

<?php
interface Decorable
{

    public function getTarget();

}


interface ClientDecorable extends Decorable
{

    public function getClient();

}


interface LogDecorable extends Decorable
{

    public function getLog();

}

abstract class AbstractDecorator implements Decorable 
{

    private $target;

    public function __construct(ClientDecorable $target)
    {
        $this->target = $target;
    }

    public function getTarget()
    {
        // I'll be able to access the leaf node of my decorator single way 'tree'
        return $this->target->getTarget();
    }

    public function __call($method, $args) {

        $reflected = new ReflectionClass($this->target);
        if ($reflected->hasMethod($method)) {
            return call_user_func_array([$this->target, $method], $args);
        }
    }

}

class ClientDecorator extends AbstractDecorator implements ClientDecorable
{
    public function __construct(Decorable $target) {
        if (! $target->getTarget() instanceof ClientDecorable) {
            throw new Exception('Must be an instance de ClientDecorable');
        }
        parent::__construct($target);
    }
    public function getClient()
    {
        return new Client($this->getTarget()->getClient());
    }

}

class LogDecorator extends AbstractDecorator implements LogDecorable
{
    public function __construct(Decorable $target) {
        if (! $target->getTarget() instanceof LogDecorable) {
            throw new Exception('Must be an instance de LogDecorable');
        }
        parent::__construct($target);
    }

    public function getLog()
    {
        return new Log($this->getTarget()->getLog());
    }

}

abstract class AbstractTarget implements Decorable
{
    // this does the trick
    public function getTarget() { return $this; }
}

trait ClientDecorableTrait {
    public function getClient()
    {
        return $this->client;
    }
}

trait LogDecorableTrait {
    public function getLog()
    {
        return $this->log;
    }
}



class Payment extends AbstractTarget implements ClientDecorable, LogDecorable
{
    use ClientDecorableTrait;
    use LogDecorableTrait;

    private $client = 1;
    private $log = 101;
}

class Sale extends AbstractTarget implements ClientDecorable
{
    use ClientDecorableTrait;

    private $client = 2;

}

class Client
{

    // ...

}


class Log
{

    // ...

}

$sale = new Sale();
var_dump($sale->getClient());
$saleDec = new ClientDecorator($sale);
var_dump($saleDec->getClient());

$payment = new Payment();
var_dump($payment->getClient());
$paymentDec = new ClientDecorator($payment);
var_dump($paymentDec->getClient());

var_dump($paymentDec->getLog());
$paymentDecTwice = new LogDecorator($paymentDec);
var_dump($paymentDecTwice->getLog());

$saleDecTwice = new LogDecorator($saleDec); // will throw an exception

これは単なるスケルトンであり、実際の実装には注意が必要です。デコレータを分けたほうがいいと思います...

于 2013-11-12T23:52:37.677 に答える
0

どのように振る舞うべきか、どのクラスになりすますべきかを伝えるパラメータをコンストラクタに渡すデコレータ クラスをいつでもインスタンス化できます。デコレータを別のクラスの拡張として宣言する必要はありません。

PHP クラスは、オブジェクトが偽装しているクラスに呼び出しを転送できるようにする魔法のメソッドextendsをサポートしています。

例えば:

class Client
{
    public function getId() { return 123; }
}

class Decorator
{
    private $instance = null;

    public function __construct($class)
    {
        $this->instance = new $class();
    }

    public function __call($method, $params) // magic method
    {
        return call_user_func_array(array($this->instance, $method), $params);
    }
}

$object = Decorator('Client');
echo $object->getId(); // 123

__call()クラスに属さないメソッドにアクセスしようとすると、マジック メソッドが呼び出されますDecorator__get()魔法のメソッドとを使用して、プロパティでも同じことができます__set()

于 2013-11-09T22:55:09.377 に答える