前言
最近看了一部英劇《黑鏡》,片中講述科技與人性碰撞可能帶來(lái)的一系列社會(huì)負(fù)影響,包括泛娛樂(lè)社會(huì)對(duì)底層人民精神的麻木作用、人工智能可能帶來(lái)的將短期痛苦無(wú)限延長(zhǎng)等等影響夷都,感慨萬(wàn)分,在這里極力推薦大伙看看這部神劇吴旋。不扯了损肛,下面開始聊聊裝飾者模式。
定義
先給出裝飾者模式的定義(來(lái)自維基百科):裝飾者模式荣瑟,是面向?qū)ο缶幊填I(lǐng)域中,一種動(dòng)態(tài)地往一個(gè)類中添加新的行為的設(shè)計(jì)模式摩泪。就功能而言笆焰,修飾模式相比生成子類更為靈活,這樣可以給某個(gè)對(duì)象而不是整個(gè)類添加一些功能见坑。裝飾者模式出現(xiàn)的意義是解決了運(yùn)行時(shí)類功能的拓展嚷掠,使得可以在運(yùn)行時(shí)進(jìn)行任一功能組合而不是需要為每種組合設(shè)計(jì)一個(gè)類(參見javaIO的設(shè)計(jì))
相關(guān)設(shè)計(jì)原則
裝飾者模式遵循開放-關(guān)閉原則捏检,及類應(yīng)該對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉的原則不皆。也就是說(shuō)我們?cè)陧?xiàng)目開發(fā)過(guò)程中應(yīng)盡量減少對(duì)已完成部分的修改贯城,把重心放在功能的拓展至上。
基本結(jié)構(gòu)
這里我們通過(guò)UML類圖來(lái)直觀地理解裝飾者模式的結(jié)構(gòu)霹娄。如圖:
這里有幾個(gè)地方需要注意一下:裝飾者與被裝飾者繼承自同一個(gè)抽象類或者接口(Component)的原因:我們利用多態(tài)能犯,通過(guò)將裝飾者與被裝飾者繼承自同一父抽象類或者接口實(shí)現(xiàn)被繼承者在被裝飾后類型不變的目的,也可以實(shí)現(xiàn)被裝飾者相互修飾的目的犬耻。第二個(gè)需要注意的是踩晶,每個(gè)裝飾者必須寫好它們的描述屬性,便于后期檢查維護(hù)枕磁。
實(shí)例
下面利用一個(gè)例子來(lái)講解裝飾者模式的使用方法渡蜻。下面的例子純屬瞎扯我們的主角VinceBarry是一名NBA新秀,他想要提高自己的籃球能力计济,通過(guò)學(xué)習(xí)模仿一些巨星的技巧是他最終選擇的方案茸苇。于是他先學(xué)習(xí)了杜蘭特的跳投技巧,然后不過(guò)癮又學(xué)習(xí)了庫(kù)里的三分球和歐文的運(yùn)球技巧沦寂,最終他的能力達(dá)到了130超過(guò)了2k的上限……扯遠(yuǎn)了学密,下面我們利用代碼來(lái)為VinceBarry增加能力。
創(chuàng)建組件抽象類
首先我們需要一個(gè)父抽象類凑队,這里我們命名為PlayBasketball则果。下面是他的具體實(shí)現(xiàn):
abstract class PlayBasketball {
String description;
public String getDescription(){
return description;
}
public abstract int score();
}
這里我們?yōu)閂inceBarry和技能們抽象出了兩個(gè)共有的屬性:描述和技能值。從這里也可以看出這個(gè)抽象類應(yīng)該是裝飾者和被裝飾者共有屬性方法的容器漩氨。
創(chuàng)建裝飾者抽象類
下面我們?cè)賱?chuàng)建技能包的抽象類(對(duì)照上面的UML類圖)西壮,我們?nèi)∶麨锽asketballSkill,下面貼上代碼:
abstract class BasketballSkill extends PlayBasketball {
public abstract String getDescription();
}
這個(gè)類繼承自父抽象類PlayBasketball叫惊,類中有一個(gè)方法用于描述不同的裝飾者款青,這個(gè)是裝飾者必須實(shí)現(xiàn)的方法。
創(chuàng)建各種裝飾者
接下來(lái)就是創(chuàng)建各種技能了霍狰,這里我創(chuàng)建了三個(gè)技能:CurryThreePoint抡草,DurantJumpShoot,IrvingDribbling蔗坯。由于后兩個(gè)代碼與第一個(gè)類似康震,我就只展示CurryThreePoint這項(xiàng)技能的代碼了。
class CurryThreePoint extends BasketballSkill {
private PlayBasketball playBasketball;
CurryThreePoint(PlayBasketball playBasketball) {
this.playBasketball = playBasketball;
}
@Override
public String getDescription() {
return playBasketball.getDescription()+" has curry's three point skill";
}
@Override
public int score() {
return 40 + playBasketball.score();
}
}
下面闡述一下這個(gè)類中的幾個(gè)關(guān)鍵點(diǎn):首先是繼承自裝飾者父類宾濒,所以必須重寫getDescription()方法腿短。然后我們重寫最關(guān)鍵的方法:score()。這個(gè)方法的特點(diǎn)是,將裝飾者中的特定行為與傳入的被裝飾者(也可能是裝飾者)的行為進(jìn)行疊加橘忱,這里的裝飾者是我們?cè)跇?gòu)造方法中傳入的Playbasketball類型的對(duì)象赴魁。通過(guò)這種方式實(shí)現(xiàn)了對(duì)象行為的修改或功能的拓展。也就是在這里我們?yōu)閂inceBarry加上了庫(kù)里三分球的能力钝诚。
測(cè)試代碼
下面我們測(cè)試一下整個(gè)流程(關(guān)于裝飾者的構(gòu)建颖御,在工廠和生成器模式中有更加優(yōu)秀的方案,日后再扯):
public class Court {
public static void main(String[] args) {
PlayBasketball vinceBarry = new VinceBarry();
System.out.println(vinceBarry.getDescription() + " " + vinceBarry.score());
vinceBarry = new DurantJumpShoot(vinceBarry);
vinceBarry = new CurryThreePoint(vinceBarry);
vinceBarry = new IrvingDribbling(vinceBarry);
System.out.println(vinceBarry.getDescription() + " " + vinceBarry.score());
}
}
輸出結(jié)果為
總結(jié)
又到一學(xué)期快結(jié)束的時(shí)間段了凝颇,想想近來(lái)自己也沒(méi)學(xué)啥潘拱,贈(zèng)給自己一句話:就是干!