**小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也不用知道具體的構件,使用者可以根據需要增加新的具體構件類和具體裝飾類,在使用時再對其進行組合,原有程式碼無須改變,符合“開閉原則”。
②裝飾模式是繼承關係的一個替代方案。裝飾模式與繼承關係的目的都是要擴充套件物件的功能,但是裝飾模式可以提供比繼承更多的靈活性。
③通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行為的組合。 -
缺點:
①這種比繼承更加靈活機動的特性,也同時意味著裝飾模式比繼承更加易於出錯,排錯也很困難,對於多次裝飾的物件,除錯時尋找錯誤可能需要逐級排查,較為煩瑣。
②使用裝飾模式進行系統設計時將產生很多小物件,這些裝飾類和小物件的產生將增加系統的複雜度,加大學習與理解的難度。