Java設計模式之裝飾者模式

hongri_999發表於2020-12-13

目錄

裝飾者模式是結構性設計模式之一,其在不必改變類檔案及不使用繼承的情況下,動態地擴充套件一個物件的功能。它通過建立一個包裝物件(即裝飾)來包裹真實的物件。

一、定義

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

裝飾著模式的結構圖:
裝飾膜模式結構圖
如上結構圖所示,裝飾者模式中有如下角色:

  • Component:可以是介面或者是抽象類,被裝飾的最原始的物件。
  • ConcreteComponent:元件具體實現類。Component的具體實現,被裝飾的具體物件【即包含原有功能的物件】。
  • Decorator:抽象裝飾者,新增裝飾類,用來擴充套件原有Component類的功能,對於Component來說無須知道Decorator的存在,所以在它的屬性中必然有一個private變數指向Component抽象元件。
  • ConcreteDecorator:裝飾者的具體實現類。

二、具體實現

裝飾者模式在生活中有很多例子,我們這裡來給一個普通的人【原來只會走路】學運動技能【新學會了游泳 + 拳擊】後變大師的例子來說明。

(1)抽象元件
我們先定義一個人的抽象類,裡面有運動的抽象方法。

public abstract class Person {
	/**
	 * Person 人有可以運動的抽象方法
 	 */
	public abstract void sport();
}

(2)元件具體實現類
被裝飾的具體物件,這裡是具體的一個普通人,作為一個普通人他當然會運動,當然在未被裝飾的情況下他只會走路。

public class CommonPerson extends Person {
	@Override
	public void sport() {
		System.out.println("普通人運動只會走路");
	}
}

(3)抽象裝飾者:
抽象裝飾者保證了一個對抽象元件的引用,方便呼叫被裝飾物件中的方法。在這裡運動大師需要持有人(Person)的引用,方便教授他其他運動,最終成為運動健將。

public abstract class Master extends Person {
	private Person mPerson;
	public Master(Person person) {
		mPerson = person;
	}
	@Override
	public void sport() {
		mPerson.sport();
	}
}

(4)裝飾者具體實現類:
這裡有兩個裝飾者具體實現類,分別是寧澤濤跟鄒市明,他們(裝飾者)負責向普通人(被裝飾者)教授游泳跟拳擊。

public class Ningzetao extends Master {
	public Ningzetao(Person person){
		super(person)
	}
	@Override
	public void sport() {
		super.sport();
		teachSwimming();
	}
	public void teachSwimming(){
		System.out.println("寧澤濤教普通人游泳");
	}
}
public class Zoushiming extends Master {
	public Zoushiming(Person person){
		super(person)
	}
	@Override
	public void sport() {
		super.sport();
		teachBoxing();
	}
	public void teachBoxing(){
		System.out.println("鄒市明教普通人拳擊");
	}
}

(5)客戶端呼叫:
經過寧澤濤跟鄒市明的教導後,普通人經過裝飾後,除了會走路之外,也學會了游泳跟拳擊。

public class Client {
	public static void main (String[] args) {
		//建立普通人,只會走路
		CommonPerson mCommonPerson = new CommonPerson();
		
		//寧澤濤教普通人學游泳,普通人學會了游泳
		Ningzetao mNingzetao = new Ningzetao(mCommonPerson);
		mNingzetao.sport();
		
		//鄒市明教普通人學拳擊,普通人學會了拳擊
		Zoushiming mZoushiming = new Zoushiming(mCommonPerson);
		mZoushiming.sport();
	}
}

三、使用場景

  • 在不影響其他物件的情況下,以動態、透明的方式給單個物件新增職責。
  • 需要動態地給一個物件新增功能,這些功能可以動態的撤銷。
  • 當不能採用繼承的方式對系統進行擴充或者採用繼承不利於系統擴充套件和維護時。

四、優缺點

優點

  • 通過組合而非繼承的方式,動態地擴充套件一個物件的功能,在執行時可以選擇不同的裝飾器從而實現不同的功能。
  • 有效的避免了使用繼承的方式擴充套件物件功能而帶來的靈活性差、子類無限制擴張的問題。
  • 具體元件類與具體裝飾類可以獨立變化,使用者可以根據需要新增具體元件類跟裝飾類,在使用時在對其進行組合,原有程式碼無須改變,符合"開閉原則"。

缺點

  • 因為所有物件均繼承於Component,所以如果Component內部結構發生改變,則不可避免地影響到所有子類(裝飾者於被裝飾者)。如果基類改變,則勢必影響物件的內部。
  • 裝飾模式比繼承更容易出錯,拍錯也比較困難。對於多次裝飾的物件,除錯時尋找錯誤可能需要逐級排查,較為繁瑣。所以一般只在必要的時候使用裝飾者模式。
  • 裝飾層數不能過多,否則會影響效率。

相關文章