小白設計模式:裝飾者模式

定義

可以動態的給對象增長行爲職責的一種模式,靈活性遠勝於繼承。bash

主要組成

抽象組件(Component): 定義抽象行爲接口。微信

具體組件(Concrete component): 定義具體實現行爲接口的類,繼承自抽象組件,也作被裝飾者,用於被附加各類行爲。框架

抽象裝飾者(Decorator):持有一個Component的引用,並繼承自Component,提供其一致的接口。這邊繼承自Component來達到類型匹配的效果,而不是爲了利用繼承來獲取行爲,行爲來自裝飾者與基礎組件的組合關係ide

具體裝飾者(Concrete Decorator):負責給Component組件對象添加具體的責任,繼承自Decorator學習

UML類圖

框架代碼

抽象組件(Component):ui

public interface Component {
	void methodA();
	void methodB();
}
複製代碼

具體組件(Concrete component):this

public class ConcreteComponent implements Component{
	@Override
	public void methodA() {
		//...
		
	}

	@Override
	public void methodB() {
		//...
		
	}
}
複製代碼

抽象裝飾者(Decorator):spa

public abstract class Decorator implements Component{
	Component component;
	
	public  Decorator(Component component) {
		this.component = component;
	}
}
複製代碼

具體裝飾者(Concrete Decorator):設計

public class ConcreteDecoratorA extends Decorator{
	
	public ConcreteDecoratorA(Component component) {
		super(component);
	}

	@Override
	public void methodA() {
		component.methodA();
		//...裝飾者擴展Component狀態
		
	}

	@Override
	public void methodB() {
		component.methodB();
		//...裝飾者擴展Component狀態
		
	}

}

public class ConcreteDecoratorB extends Decorator{

	public ConcreteDecoratorB(Component component) {
		super(component);
	}

	@Override
	public void methodA() {
		//...
	}

	@Override
	public void methodB() {
		//...
	}

}
複製代碼

具體例子

以銷售咖啡爲例,爲咖啡店設計實現飲料售價的類結構,假設存在: 咖啡種類:美式咖啡(American coffee)、英式咖啡(English coffee)、拿鐵(Latte),售價分別爲每杯15,16,17元。 配料種類:蒸奶(Milk)、豆漿(Soy)、摩卡(Mocha),售價爲每份3,1,2元。code

UML類圖

代碼

Beverage(對應抽象組件Component):

public interface Beverage {
	float cost();
}
複製代碼

Coffee(對應具體組件Concrete component):

美式咖啡:

public class AmericanCoffee implements Beverage{

	@Override
	public float cost() {
		return 15;
	}

}
複製代碼

英式咖啡:

public class EnglishCoffee implements Beverage{

	@Override
	public float cost() {
		return 16;
	}

}
複製代碼

拿鐵:

public class Latte implements Beverage{

	@Override
	public float cost() {
		return 17;
	}
}
複製代碼

調料(對應抽象裝飾者Decorator):

public abstract class Decorator implements Beverage{
	
	Beverage beverage;
	public Decorator(Beverage beverage) {
		this.beverage = beverage;
	}
}
複製代碼

具體調料(對應具體裝飾者Concrete Decorator):

蒸奶:

public class Milk extends Decorator{

	public Milk(Beverage beverage) {
		super(beverage);
	}

	@Override
	public float cost() {
		return beverage.cost() + 3;
	}
}
複製代碼

豆漿:

public class Soy extends Decorator{

	public Soy(Beverage beverage) {
		super(beverage);
	}

	@Override
	public float cost() {
		return beverage.cost() + 1;
	}
}
複製代碼

摩卡:

public class Mocha extends Decorator{

	public Mocha(Beverage beverage) {
		super(beverage);
	}

	@Override
	public float cost() {
		return beverage.cost() + 2;
	}
}
複製代碼

客戶端調用

點一杯美式咖啡加蒸奶、豆漿 , 以及一杯英式咖啡加蒸奶、雙份摩卡,各自計算總價:

//計算美式咖啡加蒸奶、豆漿的總價
	Beverage americanCoffee = new AmericanCoffee();
	float cost = new Soy(new Milk(americanCoffee)).cost();
	System.out.println(cost + "");
	
	//計算美式咖啡加蒸奶、雙份摩卡的總價
	Beverage englishCoffee = new EnglishCoffee();
	cost = new Mocha(new Mocha(new Milk(englishCoffee))).cost();
	System.out.println(cost + "");
複製代碼

假設不使用裝飾者模式

不使用裝飾者模式,而是都統一採用繼承的方式來解決的話,會致使類數量上呈現爆炸式增長,以下uml圖所示(只列出部分),而且這仍是未考慮所有添加混合調料或者多份重複調料的狀況下的一種類圖結構,數量明顯多於上面的裝飾者模式。 一旦新增長一種coffee或者新增長一種具體調料、或者修改價錢,則維護是致命的,涉及到要修改或者新增太多的類。

假設使用以下解決方法:

這種方案一旦增長一種新的調理,可能會致使全部的子類cost都須要跟着修改。而且單設增長一種產品好比"tea"是不容許添加mocha調料的,這種方案就沒法避免,會引入沒必要要的信息。

總結

一種動態擴展的方式,比繼承更加具備靈活性。

優勢

  1. 比繼承更靈活,動態、靈活的向對象添加刪除職責,相比之下繼承要求使用前靜態建立類對象,類數量暴漲、複雜度增大
  2. 同一特性支持複用,好比用同一裝飾者屢次裝飾(例如用"邊框"裝飾者裝飾2次就能夠達到"雙邊框"的效果)
  3. 將特性有裝飾者實現,避免基礎類須要維護太多的特性,致使職責過於複雜

缺點

可能產生許多小對象,對不理解該結構的人來說,有點難以學習

應用場景

在不影響其餘對象的狀況下,以動態、透明的方式給單個對象添加職責,避免由於組合而須要建立大量的之類。

微信公衆號

相關文章
相關標籤/搜索