Decorator_裝飾模式_PHP語言描述

Decorator_裝飾模式的定義:

動態地給一個對象添加一些額外的職責。就增加功能來說,裝飾模式比生成子類更加靈活。

應用Decorator_裝飾模式解決問題的思路:

考慮這樣一個應用場景,即靈活的實現獎金的計算。在實際的應用中,很多公司對於銷售人員的獎金計算方式五花本門,並且經常變動。是非常複雜的。

首先是獎金的分類,對於個人大致有個人當月業務獎金、個人累計獎金、個人業務增長獎金、及時回款獎金等等。

其次是計算獎金的金額,又有這麼幾個基數,銷售額,銷售毛利,實際回款,業務成本,獎金基數等。

看了上面獎金的計算問題,大家是不是覺得特別的頭疼,這裏我們只討論設計模式,並不真正要去實現整體的業務。簡化一下,演示用的獎金計算體系如下:

每個人當月業務獎金 = 當月銷售額 * 3%;

每個人累計獎金 = 累計銷售額 * 0.1%;

團隊獎金 = 團隊總銷售額 * 1%;

根據裝飾模式的定義來看,要用這個模式解決此業務問題,我們需要如下的結構:

Component:組件對象接口,可以給這些對象動態的添加職責

ConcreteComponent:具體的組件對象,實現組建對象接口,通常就是被裝飾器裝飾的原始對象,也就是可以給這個對象添加職責。

Decorator:所有裝飾器類的抽象父類,需要定義一個與組件接口一致的接口,並持有一個Component對象,  其實就是持有一個被裝飾的對象.

ConcreteDecorator:實際的裝飾器對象,實現具體要向被裝飾對象添加的功能。

注意:這個被裝飾的對象不一定是最原始的那個對象了,也可能是被其他裝飾器裝飾過後的裝飾器對象,反正都是實現的同一個接口,也就是同一類型。

001 <?php
002 /**
003  * Decorator_裝飾模式_PHP語言描述
004  */
005  
006 /**
007  * 計算獎金的組建接口
008  */
009 abstract class Component{
010     /**
011      * 計算某人在某階段內的獎金,有些參數在演示中並不會使用
012      * 但在實際業務實現上會用的,爲了表示這是個具體的業務方法,因此這些參數被保留了。
013      * @param $user
014      * @param $begin
015      * @param $end
016      * <a href="http://my.oschina.net/u/556800" class="referer" target="_blank">@return</a>  int 某人在某段時間內的獎金
017      */
018     public abstract  function calcPrize($user,$begin,$end);
019 }
020  
021 /**
022  * 基本的實現計算獎金的類,也是被裝飾器裝飾的對象
023  */
024 class ConcreteComponent extends Component{
025     public function calcPrize($user$begin$end){
026         //只是一個默認的實現,默認沒有獎金
027         return 0;
028     }
029 }
030  
031  
032 class TempDB{
033      
034     static $SaleMoneyList array('zs'=>10000,'ls'=>20000,'ww'=>30000);
035      
036     public static function getMonthSaleMoney($user){
037         return TempDB::$SaleMoneyList[$user];
038     }
039 }
040  
041 /**
042  * 裝飾器的接口,需要和被裝飾的對象實現同樣的接口
043  */
044 abstract class Decorator extends Component{
045     /**
046      * 持有被裝飾的組建對象
047      */
048     protected $c;
049     /**
050      * 通過構造方法傳入被裝飾的對象
051      * @param c 被裝飾的對象
052      */
053     public function __construct($c){
054         $this->c = $c;
055     }
056      
057     public function calcPrize($user$begin$end){
058         //轉調組件對象的方法
059         return $this->c->calcPrize($user,$begin,$end);
060     }
061 }
062  
063 /**
064  * 裝飾器對象,計算當月業務獎金
065  */
066 class MonthPrizeDecorator extends Decorator{
067     public function __construct($c){
068         parent::__construct($c);
069     }
070      
071     public function calcPrize($user$begin$end){
072         //1.先獲取前面運算出來的獎金
073         $money = parent::calcPrize($user$begin$end);
074         //2.然後計算當月業務獎金,按人員和時間去獲取當月業務額,然後再乘以3%
075         $prize = TempDB::getMonthSaleMoney($user) * 0.03;
076         echo $user."當月業務獎金:".$prize."<br>";
077         return $money+$prize;
078     }
079 }
080  
081 /**
082  * 裝飾器對象,計算累計獎金
083  */
084 class SumPrizeDecorator extends Decorator{
085     public function __construct($c){
086         parent::__construct($c);
087     }
088      
089     public function calcPrize($user$begin$end){
090         //1.先獲取前面運算出來的獎金
091         $money = parent::calcPrize($user$begin$end);
092         //2.然後計算累計獎金,其實應該按照人員去獲取累計的業務額,然後再乘以0.1%
093         //簡單演示一下,假定大家累計的業務額都是1000000元
094         $prize = 1000000 * 0.001;
095         echo $user."累計業務獎金:".$prize."<br>";
096         return $money $prize;
097     }
098 }
099 //先創建計算基本獎金的類,這也是被修飾的類
100 $c1 new ConcreteComponent();
101  
102 //然後對計算的基本獎金進行裝飾,這裏要組合各個裝飾
103 //說明,各個裝飾者之間最好是不要有先後順序的限制
104 //也就是先裝飾誰和後裝飾誰都應該是一樣的
105  
106 //組合普通業務人員的獎金計算
107 $d1 new MonthPrizeDecorator($c1);
108 $d2 new SumPrizeDecorator($d1);
109  
110 //注意:這裏只需要使用最後組合好的對象調用業務方法即可,會依次調用回去
111 //日期對象都沒有用上,所以傳NULL就可以了
112 $zs $d2->calcPrize('zs', null, null);
113 echo '============張三應得的獎金:'.$zs."<br>";
114 $ls $d2->calcPrize('ls', null, null);
115 echo '============李四應得的獎金:'.$ls."<br>";
116 ?>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章