3.Decorator Pattern(裝飾者模式)

裝飾者模式:ide

  動態地將責任附加到對象上。想要擴展功能,裝飾者提供有別於繼承的另外一種選擇。測試

舉例:this

  不知道你們學校的食堂是什麼點餐制度(或者你們就直接想成吃火鍋,咱們要火鍋料 + 配菜),咱們學校的點餐是:主食大米 + 你想要吃的菜(每一個菜都裝在小碗中)。如今問題來了,我點的是大米(0.8元) + 紅燒茄子(2.0元) + 荔枝肉(3.5元) + 一個雞腿(3.5元) + 炒土豆(1.0元),一共10.8元。spa

  這只是我想要吃的食品,每一個同窗點餐都不同,因此價格會隨着所點食物的不一樣而不一樣。還有一點就是咱們點餐都要點米飯(這是規定,沒有那麼多理由,就是這麼任性。其實否則,咱們須要有個主對象去修飾),那麼咱們應該怎樣實現這樣的點餐計價方式呢?3d

生活中的實例:code

  有一家咖啡店,它提供給咱們以下代碼:對象

1 public abstract class Beverage{//飲料抽象類
2     String description = "Unknown Beverage";//飲料名稱
3     
4     public String getDescription(){//獲取飲料名稱的方法
5         return description;
6     }
7     
8     public abstract double cost();//飲料價格
9 }
Beverage

  這家咖啡店有主飲料(至關於米飯):Espresso(濃縮咖啡1.99$)、HouseBlend(綜合咖啡0.89$)、DarkRoast(深焙0.99$)、Decaf(低咖啡因1.05$)四種blog

  還有各類配料:Milk(牛奶0.10$)、Mocha(摩卡0.20$)、Soy(豆漿0.15$)、Whip(奶泡0.10$)四種繼承

  咖啡店想要作出一個點飲料機器,能夠點一種主飲料再從四種配料中任意選1到4中配料。該機器能夠算出最後的總價,而且能夠顯示都點了那些東西。接口

分析:

  主飲料所有繼承自Beverage抽象類,由於店家已經給了Beverage抽象類,咱們只能採用繼承方式來實現四種主飲料類,若是沒有給建議使用接口方式實現(多用組合,少用繼承。)

主飲料咱們只實現其中兩種:

 1 public class Espresso extends Beverage{//濃縮咖啡類
 2     
 3     public Espresso(){
 4         description = "Espresso";
 5     }
 6     
 7     public double cost(){
 8         return 1.99;
 9     }
10 }
Espresso
1 public class HouseBlend extends Beverage{//綜合咖啡類
2     public HouseBlend(){
3         description = "House Blend Coffee";
4     }
5     
6     public double cost(){
7         return .89;
8     }
9 }
HouseBlend

配料也繼承自Beverage,不過咱們在中間加一個橋樑,將主飲料和配料區別對待,這樣對於之後的修改有好處:

1 public abstract class CondimentDecorator extends Beverage{//配料接口
2     public abstract String getDescription();
3 }
CondimentDecorator

  全部配料都繼承自上面的CondimentDecorator接口:

配料咱們實現其中三種:

 1 public class Mocha extends CondimentDecorator {//配料:摩卡類
 2     Beverage beverage;//每一個配料中都有一個Beverage對象,該對象存儲的是配料修飾的產品。
 3                       //關鍵就在這個對象,最後結算的時候,咱們能夠調用該對象的getDescription和cost方法
 4                       //我稱它爲盒子裏面套盒子
 5     
 6     public Mocha(Beverage beverage){
 7         this.beverage = beverage;
 8     }
 9     
10     public String getDescription(){
11         return beverage.getDescription() + ", Mocha";//調用beverage對象的getDescription()方法
12     }
13     
14     public double cost(){
15         return .20 + beverage.cost();//調用beverage對象的cost()方法
16     }
17 }
Mocha
 1 public class Soy extends CondimentDecorator {
 2     Beverage beverage;
 3     
 4     public Soy(Beverage beverage){
 5         this.beverage = beverage;
 6     }
 7     
 8     public String getDescription(){
 9         return beverage.getDescription() + ", Soy";
10     }
11     
12     public double cost(){
13         return .15 + beverage.cost();
14     }
15 }
Soy
 1 public class Whip extends CondimentDecorator {
 2     Beverage beverage;
 3     
 4     public Whip(Beverage beverage){
 5         this.beverage = beverage;
 6     }
 7     
 8     public String getDescription(){
 9         return beverage.getDescription() + ", Whip";
10     }
11     
12     public double cost(){
13         return .10 + beverage.cost();
14     }
15 }
Whip

  測試類:

 1 public class StarbuzzCoffee{
 2     
 3     public static void main(String args[]){
 4         Beverage beverage = new Espresso();//只點主飲料:Espresso
 5         System.out.println(beverage.getDescription() + " $" + beverage.cost());
 6         
 7         Beverage beverage2 = new HouseBlend();//點主飲料:HouseBlend
 8         beverage2 = new Mocha(beverage2);//在主飲料中加入Mocha配料:HouseBlend + Mocha
 9         beverage2 = new Soy(beverage2);//在飲料中加入Soy配料:HouseBlend + Mocha + Soy
10         beverage2 = new Whip(beverage2);//在飲料中加入Whip配料:HouseBlend + Mocha + Whip
11         System.out.println(beverage2.getDescription() + " $" + beverage2.cost());//結算
12         
13         Beverage beverage3 = new Whip( new Soy( new Mocha( new HouseBlend())));//這個和beverage2是同樣的只是寫法不一樣,認真觀察
14         System.out.println(beverage3.getDescription() + " $" + beverage3.cost());//結算
15     }
16 }
StarbuzzCoffee

編譯運行結果:

總結:

  主飲料和配料都繼承自相同的Beverage抽象類,不過爲了區分主飲料和配料的不一樣,咱們在配料和Beverage抽象類之間有多了一個CondimentDecorator接口。

   主飲料實現時,只要getDescription()和cost()方法返回本身的名稱和價格就好。配料中則多了一個Beverage對象,getDescription()和cost()方法不只要返回本身的名稱和價格,還要將本身修飾的Beverage對象的名稱和價格一塊兒算上。

 

在Java中的Java.io類中使用的就是裝飾者模式,有興趣能夠本身搜索資料。

思想提煉:

  1.對擴展開放,對修改關閉

相關文章
相關標籤/搜索