設計模式系列之「裝飾模式」

YoungManSter發表於2019-03-04

**小Y:**Hello,大家好,歡迎來到魂鬥羅.歸來的世界,下面讓小Y帶領大家一起去採訪一下叼煙大漢比爾·雷澤,讓大家更加理解這個粗狂的戰鬥漢子。Let`s go。!

**小Y:**你最喜歡幹什麼?

**比爾·雷澤:**最喜歡衝關打爆大機。

**小Y:**比爾,你想對觀眾說些什麼?

**比爾·雷澤:**想挑戰我,隨時奉陪!一顆不夠,給你來三顆!

小Y:……

比爾·雷澤作為魂鬥羅這麼經典的人物,原來也是一個粗狂耿直boy呀。為了儲存住他的光輝形象和讓大家更加了解他,小Y決定把比爾·雷澤的攻擊技能裝飾一番介紹給大家認識。

一、案例設想

**比爾·雷澤在戰場上在戰場上基本上用散彈槍可以橫掃小兵,但是遇到一些特殊的情況還是需要通過G5手雷、集速手雷、爆破飛彈等技能來進行輔助。**那麼如何設定這些技能才合適呢?簡單,小Y腦海中立馬閃過幾種方案:

(1)採用繼承的方式,設定一個比爾·雷澤類,有多少個技能就寫多少個子類來繼承這個比爾·雷澤類。

設計模式系列之「裝飾模式」

看完這個圖,小Y自己都蒙逼了,每增加一個技能可以組合出N個子類,這只是一個比爾·雷澤,再來個艾薇、寒鋒什麼的,那不就要加到天荒地老?

(2)直接抽象一個角色類,裡面包含了每個角色的技能。

設計模式系列之「裝飾模式」

這樣子有多少個角色就增加多少個子類就可以了,不用根據技能增加類,避免造成子類爆炸,但是,每個角色的技能是可以疊加使用的,角色越多或者技能疊加種類越多,那麼就要在超類增加越多的方法,而且直接修改超類不符合開閉原則(超類對擴充套件開放,對修改關閉)。

(3)今天的主題— 裝飾模式。

二、裝飾模式的概念

1.裝飾模式定義

裝飾模式(Decorator Pattern)是一種比較常見的模式,動態地給一個物件新增一些額外的職責(就增加功能來說,裝飾模式相比生成子類更為靈活)。

2.使用的場景

  • 需要擴充套件一個類的功能,或者給一個類新增附加職責(即核心功能不變,對其進行擴充套件)。
  • 需要增加由一些基本功能的排列組合而產生的非常大量的功能,從而使繼承關係變的不現實,使得子類數目呈爆炸性增長。

3.角色介紹

設計模式系列之「裝飾模式」
  • Component抽象構件

    Component是一個介面或者是抽象類,就是定義我們最核心的物件,也就是最原始的物件(在裝飾模式中,必然有一個最基本、最核心、最原始的介面或抽象類充當Component抽象構件) 。

  • ConcreteState具體狀態角色

    ConcreteComponent 具體構件,是Component的具體實現,要裝飾的就是它 。

  • Decorator裝飾角色

    一般是一個抽象類,實現Component介面或者抽象方法,它裡面可不一定有抽象的方法呀,在它的屬性裡必然有一個private變數指向Component抽象構件(如果具體裝飾角色只有一個,這個可以省略)。

  • ConcreteDecorator具體裝飾角色

    把你最核心的、最原始的、最基本的東西裝飾成想要的東西。

4.案例實現

(1)裝飾模式實現角色裝飾UML圖

設計模式系列之「裝飾模式」

①抽象角色類

public abstract class Character {
	public abstract void attack();
} 
複製程式碼

②實現角色比爾·雷澤(對它進行裝飾)

public class BillRizer extends Character {
	@Override
	public void attack() {
		//角色最基本的技能
		System.out.print("散彈槍進行掃射!");
	}
}
複製程式碼

③技能裝飾抽象類

public abstract class SkillDecorator extends Character{
	private Character character;

	public SkillDecorator(Character character) {
		this.character = character;
	}

	@Override
	public void attack() {
		this.character.attack();
	}
}
複製程式碼

④G5手雷技能

public class G5GrenadeDecorator extends SkillDecorator {
	public G5GrenadeDecorator(Character character) {
		super(character);
	}

	@Override
	public void attack() {
		super.attack();
		System.out.print("G5手雷輔助攻擊!");
	}
}
複製程式碼

⑤集速手雷技能

public class SetspeedDecorator extends SkillDecorator {
	public SetspeedDecorator(Character character) {
		super(character);
	}

	@Override
	public void attack() {
		super.attack();
		System.out.print("集速手雷輔助!");
	}
}
複製程式碼

⑥爆破飛彈技能

public class ExplosiveMissileDecorator extends SkillDecorator {
	public ExplosiveMissileDecorator(Character character) {
		super(character);
	}

	@Override
	public void attack() {
		super.attack();
		System.out.print("爆破飛彈輔助!");
	}
}
複製程式碼

⑦客戶端

public class Client {
	public static void main(String[] args){
		//需要裝飾的BillRizer
		BillRizer billRizer=new BillRizer();
		//使用G5手雷輔助
		G5GrenadeDecorator g5GrenadeDecorator=new G5GrenadeDecorator(billRizer);
		g5GrenadeDecorator.attack();
	
		//使用G5手雷+集速手雷+爆破飛彈輔助
		SetspeedDecorator setspeedDecorator=new SetspeedDecorator(g5GrenadeDecorator);
		ExplosiveMissileDecorator explosiveMissileDecorator=new ExplosiveMissileDecorator(setspeedDecorator);
		explosiveMissileDecorator.attack();
	}
}
複製程式碼

輸出結果:

①散彈槍進行掃射!G5手雷輔助攻擊!
②散彈槍進行掃射!G5手雷輔助攻擊!集速手雷輔助!爆破飛彈輔助!
複製程式碼

把比爾·雷澤的技能介紹一番,大家會發現原來這個看似粗狂的大漢真的霸氣十足啊,有資格看你不爽就來一句“想挑戰我,隨時奉陪!一顆不夠,給你來三顆”。

三、總結分析

  • 優點:
    ①裝飾類和被裝飾類可以獨立發展,而不會相互耦合。Component類無須知道Decorator類,而Decorator也不用知道具體的構件,使用者可以根據需要增加新的具體構件類和具體裝飾類,在使用時再對其進行組合,原有程式碼無須改變,符合“開閉原則”。
    ②裝飾模式是繼承關係的一個替代方案。裝飾模式與繼承關係的目的都是要擴充套件物件的功能,但是裝飾模式可以提供比繼承更多的靈活性。
    ③通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行為的組合。

  • 缺點:
    ①這種比繼承更加靈活機動的特性,也同時意味著裝飾模式比繼承更加易於出錯,排錯也很困難,對於多次裝飾的物件,除錯時尋找錯誤可能需要逐級排查,較為煩瑣。
    ②使用裝飾模式進行系統設計時將產生很多小物件,這些裝飾類和小物件的產生將增加系統的複雜度,加大學習與理解的難度。

看到裝飾模式很多小夥伴會發現跟代理模式很相似,下一篇小Y會對這兩種模式進行對比,請期待!!!!

簡書地址:http://www.jianshu.com/p/d7a9208c6829

Android技術交流吧

相關文章