“戲”說設計模式——責任鏈模式
首先請出今天的主人公——“齊天大聖”孫悟空
原創文章,禁止轉載https://blog.csdn.net/wfy2695766757
小時候每到假期,電視上就會播出大家耳熟能詳的“西遊記” 。
那麼今天我們就通過“齊天大聖”孫悟空大鬧天宮來描述23種設計模式中之一的“責任鏈模式”
首先我們先了解一下大鬧天宮的故事大概:西遊記中,孫悟空去東海龍宮搶了金箍棒,又去地府強銷生死簿。龍王、閻君去天庭告狀,玉帝把孫悟空召入天庭,授他做弼馬溫。悟空嫌官小,打回花果山,自稱“齊天大聖”。玉帝派托塔天王李靖率天兵天將捉拿孫悟空,沒有成功,便讓孫悟空管理蟠桃園。孫悟空偷吃蟠桃,毀了王母的蟠桃宴,又偷吃了
在這個故事中有四個關鍵人物分別為:孫悟空、托塔天王李靖、玉帝、如來佛祖
他們的關係圖為:
根據劇情發展,我們得到一個規律:孫悟空打敗了托塔天王李靖,打敗了玉帝,缺敗在瞭如來佛祖的手中。從中得知如來佛祖是最厲害的,沒有人能打敗他。
根據以上人物關係,我們來通過java描述他們的基本資訊:
public class LiJIng {//“托塔天王”李靖 private String name; public LiJIng(String name) { this.name = name; } public boolean fighting(String SunWuKong){ if ( ! SunWuKong.equals("孫悟空")){//判斷是否是與孫悟空打鬥 System.out.println( name + "打敗挑戰者,挑戰者被李靖治罪!"); //若不是孫悟空,則李靖打敗挑戰者 return true; }else{ System.out.println("孫悟空打敗" + name + "繼續前進,衝向天宮"); //若是孫悟空,孫悟空打敗李靖,繼續前進 return false; } } }
public class YuHuangDaDi {//玉皇大帝 private String name; public YuHuangDaDi(String name) { this.name = name; } public boolean fighting(String SunWuKong){ if ( ! SunWuKong.equals("孫悟空")){ System.out.println( name + "打敗挑戰者,挑戰者被玉帝治罪!"); //若不是孫悟空,則玉帝打敗挑戰者 return true; }else{ System.out.println("孫悟空打敗" + name + "佔領天宮,獲得“齊天大聖”稱號"); //若是孫悟空,孫悟空打敗玉帝,佔領天宮 return false; } } }
public class RuLaiFoZu {//如來佛祖
private String name;
public RuLaiFoZu(String name) {
this.name = name;
}
public boolean fighting(String SunWuKong) {
if (!SunWuKong.equals("孫悟空")) {
System.out.println( name + "打敗挑戰者,挑戰者被如來佛祖治罪!");
//若不是孫悟空,則如來佛祖打敗挑戰者
return true;
}else{
System.out.println("孫悟空被" + name + "打敗,孫悟空被壓在五指山下,大鬧天宮結束!");
//若是孫悟空,孫悟空被佛祖壓在五指山下
return false;
}
}
}
接下來,我們設定一個場景“天宮”,所有人都在這個場景裡展開故事情節
/**
* @Author by 飛宇
* @Date 2018/12/19 20:16
*/
public class TianGong {//天宮作為場景
public static void main(String[] args) {
String SunWuKong = "孫悟空";//孫悟空出場
LiJIng liJIng = new LiJIng("李靖");
if ( ! liJIng.fighting(SunWuKong)){
YuHuangDaDi yuHuangDaDi = new YuHuangDaDi("玉帝");
if ( ! yuHuangDaDi.fighting(SunWuKong)){
RuLaiFoZu ruLaiFoZu = new RuLaiFoZu("如來佛祖");
ruLaiFoZu.fighting(SunWuKong);
}
}
}
}
我們看看故事的發展情況:
功夫不負有心人,跑了三個地方和三個人打鬥,孫悟空終於完成了大鬧天宮的故事。
然而,我們的故事情節是不是有點過於複雜了,找這個打找那個打,打來打去好像孫悟空有點不耐煩了。
他說:“俺老孫打半天打累了,你們為什麼這麼麻煩,就不能一次都打完了嘛!?”
於是我們根據責任鏈模式來改進故事的發展情節:
進一步分析,挑戰的神仙肯定是不同的,並且每個神仙的戰鬥力會有區別,所以我們得把這些神仙的打鬥情節分開來寫,對每個神仙的打鬥情節我們進行定義,讓打鬥的神仙只知道自己是否能打過孫悟空(責任),如果打不過就讓更厲害的神仙去打(鏈條),開始重新定義情節,先抽象出一個神仙的類。
這回我的孫大聖分為三個等級分別為:初級孫悟空,中級孫悟空,高階孫悟空。初級只能打敗李靖,中級可以打敗李靖和玉帝,高階被如來佛祖打敗。
public abstract class ShenXian {//神仙的抽象類
protected String name;// 抽象出神仙的姓名
protected ShenXian bigShenXian;//更強大的神仙
public ShenXian(String name) {
this.name = name;
}
protected ShenXian setBigShenXian(ShenXian bigShenXian){
this.bigShenXian = bigShenXian;
return this.bigShenXian; //返回更強大的神仙,鏈式責任制度
}
public abstract void fighting(String SunWuKong);//抽象劇情發展由打鬥場景實現。
}
在第3行,神仙認識比自己更厲害的神仙,所以他可以請更厲害的神仙 ,持有強大神仙的引用。
在第9行,將強大神仙注入進來。
在第14行,是我們的情節推動,孫悟空將在這個場景中打鬥。
public class LiJIng extends ShenXian{
public LiJIng(String name) {
super(name);
}//“托塔天王”李靖
@Override
public void fighting(String SunWuKong){
if ( SunWuKong.equals("初級孫悟空")){//判斷是否是與孫悟空打鬥
System.out.println( name + "打敗初級孫悟空,初級孫悟空被李靖治罪!");
//若不是孫悟空,則李靖打敗挑戰者
}else{
System.out.println("孫悟空打敗" + name + "繼續前進,衝向天宮");
//若是孫悟空,孫悟空打敗李靖,繼續前進
this.bigShenXian.fighting(SunWuKong);
}
}
}
在第14行,表明自己打不過孫悟空,請強大神仙代替自己打鬥。
public class YuHuangDaDi extends ShenXian{
public YuHuangDaDi(String name) {
super(name);
}//玉皇大帝
@Override
public void fighting(String SunWuKong){
if (SunWuKong.equals("中級孫悟空")){
System.out.println( name + "打敗挑戰者,挑戰者被玉帝治罪!");
//若不是孫悟空,則玉帝打敗挑戰者
}else{
System.out.println("孫悟空打敗" + name + "佔領天宮,獲得“齊天大聖”稱號");
//若是孫悟空,孫悟空打敗玉帝,佔領天宮
this.bigShenXian.fighting(SunWuKong);
}
}
}
public class RuLaiFoZu extends ShenXian{
public RuLaiFoZu(String name) {
super(name);
}//如來佛祖
@Override
public void fighting(String SunWuKong) {
if (SunWuKong.equals("高階孫悟空")) {
System.out.println( name + "打敗挑戰者,挑戰者被如來佛祖治罪!");
//若不是孫悟空,則如來佛祖打敗挑戰者
}else{
System.out.println("孫悟空被" + name + "打敗,孫悟空被壓在五指山下,大鬧天宮結束!");
//若是孫悟空,孫悟空被佛祖壓在五指山下
this.bigShenXian.fighting(SunWuKong);
}
}
}
/**
* @Author by 飛宇
* @Date 2018/12/19 20:16
*/
public class TianGong {//天宮作為場景
public static void main(String[] args) {
ShenXian shenXian = new LiJIng("李靖");
shenXian.setBigShenXian(new YuHuangDaDi("玉帝"))
.setBigShenXian(new RuLaiFoZu("如來佛祖"));
shenXian.fighting("初級孫悟空");
/**
* 李靖打敗初級孫悟空,初級孫悟空被李靖治罪!
*/
shenXian.fighting("中級孫悟空");
/**
* 孫悟空打敗李靖繼續前進,衝向天宮
* 玉帝打敗挑戰者,挑戰者被玉帝治罪!v
*/
shenXian.fighting("高階孫悟空");
/**
* 孫悟空打敗李靖繼續前進,衝向天宮
* 孫悟空打敗玉帝佔領天宮,獲得“齊天大聖”稱號
* 如來佛祖打敗挑戰者,挑戰者被如來佛祖治罪!
*/
}
}
在上述程式碼中對責任鏈構造物件,(鏈式)傳遞(責任)。
這樣孫悟空就可以一次性完成打鬥,我們看到初級孫悟空只能打過李靖,而高階孫悟空才可以被如來佛祖打敗。
目的
孫悟空和重神仙實現了解耦,這樣孫悟空只需要給這條責任鏈傳遞自己的等級,便可完成自己的情節。不用操心自己是否要找到下一個神仙在開始打鬥,只需要交給神仙的介面即可。每個神仙(角色)的責任被劃分的非常清楚,然後將這些責任通過(鏈式)穿起來,形成了完整的責任範圍鏈。如果想讓孫悟空打敗更多的神仙,只需要按規範新增一個神仙(角色)到責任鏈中即可,這樣一個可伸縮的責任鏈就完成了,它擁有完美的可擴充套件性。