2013-11-09 194 views
1

我可以重複使用裝修工我可以重複使用裝飾器嗎?

我有一個ClientDecorator裝飾,有一個客戶端的參考實體,這個裝飾獲取客戶端數據庫調用getClient(它被裝飾之前,此方法返回的clientId,正在裝修後,返回客戶端的實例)。

好的,但是,我有一些其他實體可以使用相同的裝飾器進行裝飾,例如,我有另一個名爲questions的表,該表有一個指向已提出問題的客戶端的引用,而我有另一個名爲schedules的表格,它有一個客戶端的參考。

順便說一句,我可以裝飾questionscheduleClientDecorator

但是,我也有一個QuestionDecorator;這個人裝飾Answer

我怎麼可以做這個抽象,所以我可以重用裝飾器,只要我想要?

我試圖創建ClientDecorable,QuestionDecorable接口,但沒有取得任何進展。

+0

你需要定義接口。就像你寫的一樣。你的裝飾器只接受實現定義接口的組件。這是要走的路。發佈你的代碼。 – busypeoples

+0

給我一個例子@busypeoples –

+0

你有沒有注意到'Decorator'對裝飾者來說是個壞名字?你應該給事物描述性的名字......如果我們不知道你的裝飾器會改變哪些功能,很難說出你能做什麼或不能做什麼...... –

回答

0

您可以將裝飾類傳遞參數傳遞給構造函數,該構造函數將告訴它它應該如何表現或應該模仿什麼類。你並不需要將你的裝飾器聲明爲另一個類的擴展。

PHP類支持magic methods,它可以將呼叫轉發到對象正在模擬的類,就好像它正在使用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 

神奇的方法,當您嘗試訪問不屬於類Decorator的方法__call()將被調用。使用神奇方法__get()__set()也可以通過屬性完成相同的操作。

+0

這不是一個難看的方法嗎?理論上它很簡單,例如:客戶端,支付,日誌...等等:日誌可以用客戶端裝飾,支付可以用客戶端和日誌裝飾...得到想法?我看不到這個代碼:( –

+0

根本不是,我只是寫了一個例子給你一個想法 – Havenard

+0

但是,當然你願意擴展的類必須有共同的方法,如果它們完全不同,代碼你的裝飾者甚至都沒有意義吧 – Havenard

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 

這只是一個骨架,真實世界的實現必須是棘手的。我認爲你最好讓你的裝飾器分開......

相關問題