1. 程式人生 > >08 裝飾者模式(Decorator Pattern)

08 裝飾者模式(Decorator Pattern)

描述性文字

還記得工廠方法模式中示例程式碼中的奶茶店嗎?在那一節中講解的是通過工廠方法模式來做奶茶,做奶茶的工作都已經交給小弟了, 小豬的工作量少了很多。於是,寫出所有飲品的價格:

奶茶:

  • 原味奶茶:5塊
  • 珍珠奶茶:7塊
  • 椰果奶茶:7塊
  • 珍珠椰果奶茶:9塊

檸檬茶:

  • 原味檸檬茶:3塊
  • 金桔檸檬茶:5塊.

然後顧客要什麼點什麼,按著選單收費就好了,然而使用者的 需求都是多變的,他們覺得配料那裡可以加點紅豆,然後你 的選單需要新增:

  • 紅豆奶茶:7塊
  • 紅豆珍珠奶茶:9塊
  • 紅豆椰果奶茶:9塊
  • 紅豆珍珠椰果奶茶:11塊

每個組合都寫一個,這他麼得寫多少個,而且使用者總是天馬行空的,哪天希望配料加點 ,也是有可能的, 每多一種配料,就得增加一堆飲品。我們必須想一個更優的套路,這個時候可以考慮引入裝飾者模式, 簡單來說就是:一層套一層,比如說要椰果珍珠奶茶:奶茶 –> 套一層珍珠 –> 珍珠(奶茶) –> 套一層椰果 –> 椰果(珍珠(奶茶))逼逼那麼多,程式碼演示下吧!

程式碼如下

package structPattrn.decoratorPattern;

/**
 * 裝飾者模式測試例程
 *     
 * @Package       structPattrn.decoratorPattern
 * @Title:        DecoratorPatternDemo.java
 * @Company:      $
 * @author        BurgessLee 
 * @date          2018年10月16日-下午4:38:01
 * @Description:  $
 */
public class DecoratorPatternDemo {
	
	public static void main(String[] args) {
		Tea mileTea = new MilkTea();
		System.out.println("您點的是:" + mileTea.getName() +" 價格為:"+ mileTea.price());
		
		Tea lemonTea = new LemonTea();
		System.out.println("您點的是:" + lemonTea.getName() +" 價格為:"+ lemonTea.price());
		
		Tea tea3 = new MilkTea();
		System.out.println("您點的是:" + tea3.getName() +" 價格為:"+ tea3.price());
		tea3 = new ZhenZhu(tea3);
		System.out.println("您點的是:" + tea3.getName() +" 價格為:"+ tea3.price());
		tea3 = new YeGuo(tea3);
		System.out.println("您點的是:" + tea3.getName() +" 價格為:"+ tea3.price());
		tea3 = new HongDou(tea3);
		System.out.println("您點的是:" + tea3.getName() +" 價格為:"+ tea3.price());
		tea3 = new JinJu(tea3);
		System.out.println("您點的是:" + tea3.getName() +" 價格為:"+ tea3.price());
	}
	
}

//抽象茶的父類
abstract class Tea{
	private String name = "茶";

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public abstract int price();
}

//定義配料的父類
abstract class Decorator extends Tea{
	public abstract String getName();
}

class MilkTea extends Tea{
	
	public MilkTea() {
		setName("奶茶");
	}

	@Override
	public int price() {
		return 5;
	}
	
}

class LemonTea extends Tea{
	
	public LemonTea() {
		setName("檸檬茶");
	}

	@Override
	public int price() {
		return 3;
	}
	
}

class ZhenZhu extends Decorator{
	
	private Tea tea;
	
	public ZhenZhu(Tea tea) {
		super();
		this.tea = tea;
	}

	@Override
	public String getName() {
		return "珍珠" + this.tea.getName();
	}

	@Override
	public int price() {
		return 2+ this.tea.price();
	}
	
}

class YeGuo extends Decorator{
	
	private Tea tea;
	
	public YeGuo(Tea tea) {
		super();
		this.tea = tea;
	}

	@Override
	public String getName() {
		return "椰果" + this.tea.getName();
	}

	@Override
	public int price() {
		return 2+ this.tea.price();
	}
	
}

class HongDou extends Decorator{
	
	private Tea tea;
	
	public HongDou(Tea tea) {
		super();
		this.tea = tea;
	}

	@Override
	public String getName() {
		return "紅豆" + this.tea.getName();
	}

	@Override
	public int price() {
		return 2+ this.tea.price();
	}
	
}

class JinJu extends Decorator{
	
	private Tea tea;
	
	public JinJu(Tea tea) {
		super();
		this.tea = tea;
	}

	@Override
	public String getName() {
		return "金桔" + this.tea.getName();
	}

	@Override
	public int price() {
		return 2+ this.tea.price();
	}
	
}

列印結果:

您點的是:奶茶 價格為:5
您點的是:檸檬茶 價格為:3
您點的是:奶茶 價格為:5
您點的是:珍珠奶茶 價格為:7
您點的是:椰果珍珠奶茶 價格為:9
您點的是:紅豆椰果珍珠奶茶 價格為:11
您點的是:金桔紅豆椰果珍珠奶茶 價格為:13

模式要點

定義:


動態的給物件新增一些額外的職責,就增加功能來說,裝飾者模式比起生成子類更加靈活!

四個角色:

 

  1. Component:抽象元件,可以是介面或抽象類,具體元件與抽象裝飾類的共同父類,聲明瞭在具體元件中實現的業務方法,可以使客戶端以一致的方式處理未修飾物件與修飾後的物件,實現了客戶端的透明操作,比如這裡的Tea類。
  2. ConcreteComponent:具體元件,實現抽象元件中生命的方法,裝飾器類可以給他增加額外的責任(方法),比如這裡的MilkTea和LemonTea。
  3. Decorator:抽象裝飾類,裝飾元件物件的,內部一定要有一個指向元件物件的引用!!!通過該引用可以呼叫裝飾前構建物件的方法,並通過其子類擴充套件該方法,已達到裝飾的目的,比如這裡的Decorator類。
  4. ConcreteDecorator:具體裝飾類,抽象裝飾類的具體實現,可以呼叫抽象裝飾類中定義的方法,也可以新增新的方法來擴充物件的行為。

UML類圖

 

 

 

 

 

 

 

 

 

 

 

 

適用場景


裝飾者模式是以對客戶端透明的方式擴充套件物件的功能,是繼承關係的一種替代方案! 以下情況可以考慮是想用物件組合(組合與委託):在不影響其他物件的情況下,以動態、透明的方式給單個物件新增職責;處理那些可以撤消的職責;當不能採用生成子類的方法進行擴充時:一種情況是,可能有大量獨立的擴充套件, 為支援每一種組合將產生大量的子類,使得子類數目呈爆炸性增長。另一種情況可能是因為類定義被隱藏,或類定義不能用於生成子類;
 

優缺點

  • 擴充套件物件功能,比繼承靈活,不會導致類個數急劇增加;
  • 可以通過一種動態的方式在執行時選擇不同的具體裝飾類,從而實現不同的行為;
  • 避免了高層次類有太多的特徵,可以從一個最簡單的類慢慢給他新增功能;
  • 會產生很多小裝飾者物件,會影響效能,過多使用該模式也會使程式變得複雜。