2016-02-28 133 views
2

我現在就讀的裝飾圖案,在這裏一些示例代碼(PHP):裝飾模式問題 - 如何調用嵌套裝飾方法?

abstract class component{ 

    public function drawShape(){}; 

} 

class concreteComponent extends component{ 

    public function drawShape(){//code}; 

} 

class decoratorComponent extends component{ 

    private $component; 

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

    public function drawShape(){ 

     $this->component->drawShape(); 

    } 

} 

class borderDecorator extends decoratorComponent{ 

    public function drawShape(){ 

    $this->drawBorder(); 
    $this->component->drawShape(); 

    } 

    public function setBorder(){}; 
    public function drawBorder(){}; 

} 

class bgColorDecorator extends decoratorComponent{ 

    public function drawShape(){ 

    $this->drawBgColor(); 
    $this->component->drawShape(); 

    } 

    public function setbgColor(){}; 
    public function drawBgColor(){}; 

} 

好了,現在:

$test=new concreteComponent(); 
$border=new borderDecorator($test); 
$border->setBorder(10); 
$bgColor= new bgColorDecorator($border); 
$bgColor->setBgColor(#000); 

現在我有飾有#000背景色的成分,一個10(某個單位)的邊界。

隨着

$bgColor->drawShape(); 

這意味着drawBgColor + drawBorder + drawShape和所有權利,但:

如何修改或刪除邊框?

$bgColor-> ??? 

或博客類不能直接訪問邊境方法...

感謝

+0

Mhm我正在學習一本書,你可以看看它的接口,所以我有同樣的方法drawShape(),我可以稱它不用擔心,如果我使用裝飾組件或沒有(我是對的?)@PeeHaa – Francesco

+0

如果你的對象圖不是太複雜,只是在修飾器改變時重新構造整個圖。但是,如果這太多開銷,你可能會寫一個知道其他功能或插件的裝飾器。像'$ test = new ConcreteCmp(); $ pluggableCmp = new PluggableDecorator($ test); $ pluggableCmp.addFeature(new BorderFeature()); $ pluggableCmp.addFeature(new BGColorFeature())' – plalx

+0

然後從$ pluggableCmp如何調用BorderFeature或BGColorFeature的方法來修改它們? @plalx – Francesco

回答

0

據我所知你在離開了bgColorDecorator實例的方式鏈接你的裝飾從中您無法設置/刪除邊框。

你應該做的是改變結構,終點由borderDecorator部分的順序:

$test=new concreteComponent(); 

$bgColor= new bgColorDecorator($test); // pass test to bgcolor 
$bgColor->setBgColor(#000); 

$border=new borderDecorator($bgColor); // pass bgcolor to border 
$border->setBorder(10); 

// You can now set/remove border on $border 
// and of course : $border->drawShape(); 

看來,你的任務是繪製一個對象,以便繪製的正確順序要求出具在drawShape方法改變,以保持秩序背景/形狀/邊框

$this->drawBgColor(); 
$this->component->drawShape(); 
// will become a post-action 
$this->component->drawShape();  
$this->drawBgColor(); 

現在的問題是你將不能夠動態地設置的backgroundColor爲sa我的理由是。所以另一種解決方案可能是修改你的decoratorComponent接口以包含你需要的,並在decoratorComponent子類中實現它。

編輯的雙邊框情況:

剛剛鏈上的兩個borderDecorator到分量

$cmp = new concreteComponent(); 

$bDecrtor1 = new borderDecorator($cmp); // 1st border decorator on cmp 
$bDecrtor1 ->setBorder(10); 

$bDecrtor2=new borderDecorator($bDecrtor1); // 2nd border decorator on 1st one 
$bDecrtor2->setBorder(20); 

// $bDecrtor2->drawShape(); 
// You can then use bDecrtor1 or bDecrtor2 to (re)set the border properties 
// You can use bDecrtor2 to chain other decorators... 
+0

我現在不需要這個代碼,我只是想練習,然後我看不出如何裝飾者可以成爲一個靈活的解決方案......(我正在讀OOP的書)...裝飾者應該允許我動態添加/刪除動作和運行時到一個對象(裝飾),但是當我添加更多的一個裝飾器,我在最後一個添加的裝飾器變得像不可用...如果我有10個裝飾器,我不能每次修改decoratorComponent接口以添加可能的裝飾器動作,這不是模式背後的輕巧靈活的邏輯... @ floppy12 – Francesco

+0

@Francesco這是一個靈活的解決方案,您可以將裝飾器鏈接到組件以構建更多演化組件等等,實際上鍊接的順序會使源於相同源代碼的不同行爲。順便說一句,爲什麼你不使用每個裝飾器(不僅是最新的)?你可以使用他們每個人(重新)設置所需的屬性 – floppy12

+0

而在這種情況下,我想要一個雙邊框?我只能使用一個,如果我使用另一個borderDecorator來覆蓋第一個borderDecator ... @ floppty12 – Francesco

0

你可以做的是落實magic method命名__call()(一個包羅萬象的方法),嘗試委託任何不存在的方法包裝component

class decoratorComponent extends component{ 

    private $component; 

    /* ... */ 

    public function __call($name, $arguments) { 
    return call_user_func_array(array($this->component, $name), $arguments); 
    } 
} 

您只需構建安全措施即可捕獲您嘗試調用的方法最終不存在於任何組件中的情況。

但是,您應該也可以評估在之後調用裝飾器方法是否已經將它們包裝在另一個裝飾器中。

+0

我已經知道PHP的「魔術方法」,但這是一個棘手的方法,我希望解決該問題只是一個邏輯模式(獨立於特定的編程語言) – Francesco

+0

@Francesco問題在於裝飾模式通常不用於添加額外的方法,可以隨機調用,而是修改* existing *方法的行爲(可能通過構造函數參數來配置)。在你的情況下,這意味着你會通過borderDecorator的構造函數傳遞邊框大小。 –