第21章 組合模式
21.1 公司的人事架構是這樣的嗎
各位讀者,大家在上學的時候應該都學過“數據結構”這門課程吧,還記得其中有一節叫“二叉樹”吧,我們上學那會兒這一章節是必考內容,左子樹,右子樹,什么先序遍歷、后序遍歷,重點就是二叉樹的遍歷,我還記得當時老師就說,考試的時候一定有二叉樹的構建和遍歷,現在想起來還是覺得老師是正確的,樹狀結構在實際中應用非常廣泛,想想看你最常使用的XML格式是不是就是一個樹形結構。
咱就先說個最常見的例子,公司的人事管理就是一個典型的樹狀結構,想想看你公司的組織架構是不是如圖21-1所示。

圖21-1 普遍的組織架構
從最高的老大,往下一層一層的管理,最后到我們這層小兵……很典型的樹狀結構(說明一下,這不是二叉樹,有關二叉樹的定義可以翻翻以前的教科書),我們今天的任務就是要把這個樹狀結構實現出來,并且還要把它遍歷一遍,就類似于閱讀你公司的人員花名冊。
從該樹狀結構上分析,有兩種不同性質的節點:有分支的節點(如研發部經理)和無分支的節點(如員工A、員工D等),我們增加一點學術術語上去,總經理叫做根節點(是不是想到XML中的那個根節點root,那就對了),類似研發部經理有分支的節點叫做樹枝節點,類似員工A的無分支的節點叫做樹葉節點,都很形象,三個類型的節點,那是不是定義三個類就可以?好,我們按照這個思路走下去,先看我們自己設計的類圖,如圖21-2所示。

圖21-2 最容易想到的組織架構類圖
這個類圖是初學者最容易想到的類圖(首先聲明,這個類圖是有缺陷的,如果你已經看明白這個類圖的缺陷了,該段落就可以一目十行地看下去,我們是循序漸進地講課,一步一個腳印),非常簡單,我們來看一下如何實現,先看最高級別的根節點接口,如代碼清單21-1所示。
代碼清單21-1 根節點接口
public?interface?IRoot?{
?????//得到總經理的信息
?????public?String?getInfo();
?????//總經理下邊要有小兵,那要能增加小兵,比如研發部總經理,這是個樹枝節點
?????public?void?add(IBranch?branch);
?????//那要能增加樹葉節點
?????public?void?add(ILeaf?leaf);
?????//既然能增加,那還要能夠遍歷,不可能總經理不知道他手下有哪些人
?????public?ArrayList?getSubordinateInfo();?????
}
這個根節點的對象就是我們的總經理,其具體實現如代碼清單21-2所示。
代碼清單21-2 根節點的實現
public?class?Root?implements?IRoot?{
?????//保存根節點下的樹枝節點和樹葉節點,Subordinate的意思是下級
?????private?ArrayList?subordinateList?=?new?ArrayList();
?????//根節點的名稱
?????private?String?name?=?"";
?????//根節點的職位
?????private?String?position?=?"";
?????//根節點的薪水
?????private?int?salary?=?0;
?????//通過構造函數傳遞進來總經理的信息
?????public?Root(String?name,String?position,int?salary){
?????????????this.name?=?name;
?????????????this.position?=?position;
?????????????this.salary?=?salary;
?????}
?????//增加樹枝節點
?????public?void?add(IBranch?branch)?{
?????????????this.subordinateList.add(branch);
?????}
?????//增加葉子節點,比如秘書,直接隸屬于總經理
?????public?void?add(ILeaf?leaf)?{
?????????????this.subordinateList.add(leaf);
?????}
?????//得到自己的信息
?????public?String?getInfo()?{
?????????????String?info?=?"";
?????????????info?=?"名稱:"+?this.name;;
?????????????info?=?info?+?"\t職位:"?+?this.position;
?????????????info?=?info?+?"\t薪水:?"?+?this.salary;
?????????????return?info;
?????}
?????//得到下級的信息
?????public?ArrayList?getSubordinateInfo()?{
?????????????return?this.subordinateList;
?????}
}
很簡單,通過構造函數傳入參數,然后獲得信息,可以增加子樹枝節點(部門經理)和葉子節點(秘書)。我們再來看其他有分支的節點接口,如代碼清單21-3所示。
代碼清單21-3 其他有分支的節點接口
public?interface?IBranch?{
?????//獲得信息
?????public?String?getInfo();
?????//增加數據節點,例如研發部下設的研發一組
?????public?void?add(IBranch?branch);
?????//增加葉子節點
?????public?void?add(ILeaf?leaf);
?????//獲得下級信息
?????public?ArrayList?getSubordinateInfo();
}
有了接口,就應該有實現,其具體的實現類,如代碼清單21-4所示。
代碼清單21-4 分支的節點實現
public?class?Branch?implements?IBranch?{
?????//存儲子節點的信息
?????private?ArrayList?subordinateList?=?new?ArrayList();
?????//樹枝節點的名稱
?????private?String?name="";
?????//樹枝節點的職位
?????private?String?position?=?"";
?????//樹枝節點的薪水
?????private?int?salary?=?0;
?????//通過構造函數傳遞樹枝節點的參數
?????public?Branch(String?name,String?position,int?salary){
?????????????this.name?=?name;
?????????????this.position?=?position;
?????????????this.salary?=?salary;
?????}
?????//增加一個子樹枝節點
?????public?void?add(IBranch?branch)?{
?????????????this.subordinateList.add(branch);
?????}
?????//增加一個葉子節點
?????public?void?add(ILeaf?leaf)?{
?????????????this.subordinateList.add(leaf);
?????}
?????//獲得自己樹枝節點的信息
?????public?String?getInfo()?{
?????????????String?info?=?"";
?????????????info?=?"名稱:"?+?this.name;
?????????????info?=?info?+?"\t職位:"+?this.position;
?????????????info?=?info?+?"\t薪水:"+this.salary;
?????????????return?info;
?????}
?????//獲得下級的信息
?????public?ArrayList?getSubordinateInfo()?{
?????????????return?this.subordinateList;
?????}
}
不管是總經理還是部門經理都是有子節點的存在,最終的子節點就是葉子節點,其接口如代碼清單21-5所示。
代碼清單21-5 葉子節點的接口
public?interface?ILeaf?{?????
?????//獲得自己的信息
?????public?String?getInfo();
}
葉子節點的接口簡單,實現也非常容易,如代碼清單21-6所示。
代碼清單21-6 葉子節點的實現
public?class?Leaf?implements?ILeaf?{
?????//葉子叫什么名字
?????private?String?name?=?"";
?????//葉子的職位
?????private?String?position?=?"";
?????//葉子的薪水
?????private?int?salary=0;
?????//通過構造函數傳遞信息
?????public?Leaf(String?name,String?position,int?salary){
?????????????this.name?=?name;
?????????????this.position?=?position;
?????????????this.salary?=?salary;
?????}
?????//最小的小兵只能獲得自己的信息了
?????public?String?getInfo()?{
?????????????String?info?=?"";
?????????????info?=?"名稱:"?+?this.name;
?????????????info?=?info?+?"\t職位:"+?this.position;
?????????????info?=?info?+?"\t薪水:"+this.salary;
?????????????return?info;
?????}
}
好了,所有的根節點、樹枝節點和葉子節點都已經實現了,從總經理、部門經理到最終的員工都已經實現,然后的工作就是組裝成一個樹狀結構并遍歷這棵樹,通過什么來完成呢?通過場景類Client完成,如代碼清單21-7所示。
代碼清單21-7 場景類
public?class?Client?{
?????public?static?void?main(String[]?args)?{
?????????????//首先產生了一個根節點
?????????????IRoot?ceo?=?new?Root("王大麻子","總經理",100000);
?????????????//產生三個部門經理,也就是樹枝節點
?????????????IBranch?developDep?=?new?Branch("劉大瘸子","研發部門經理",10000);
?????????????IBranch?salesDep?=?new?Branch("馬二拐子","銷售部門經理",20000);
?????????????IBranch?financeDep?=?new?Branch("趙三駝子","財務部經理",30000);
?????????????//再把三個小組長產生出來
?????????????IBranch?firstDevGroup?=?new?Branch("楊三乜斜","開發一組組長",5000);
?????????????IBranch?secondDevGroup?=?new?Branch("吳大棒槌","開發二組組長",6000);
?????????????//剩下的就是我們這些小兵了,就是路人甲、路人乙
?????????????ILeaf?a?=?new?Leaf("a","開發人員",2000);
?????????????ILeaf?b?=?new?Leaf("b","開發人員",2000);
?????????????ILeaf?c?=?new?Leaf("c","開發人員",2000);
?????????????ILeaf?d?=?new?Leaf("d","開發人員",2000);
?????????????ILeaf?e?=?new?Leaf("e","開發人員",2000);
?????????????ILeaf?f?=?new?Leaf("f","開發人員",2000);
?????????????ILeaf?g?=?new?Leaf("g","開發人員",2000);
?????????????ILeaf?h?=?new?Leaf("h","銷售人員",5000);
?????????????ILeaf?i?=?new?Leaf("i","銷售人員",4000);
?????????????ILeaf?j?=?new?Leaf("j","財務人員",5000);
?????????????ILeaf?k?=?new?Leaf("k","CEO秘書",8000);
?????????????ILeaf?zhengLaoLiu?=?new?Leaf("鄭老六","研發部副總",20000);
?????????????//該產生的人都產生出來了,然后我們怎么組裝這棵樹
?????????????//首先是定義總經理下有三個部門經理
?????????????ceo.add(developDep);
?????????????ceo.add(salesDep);
?????????????ceo.add(financeDep);
?????????????//總經理下還有一個秘書
?????????????ceo.add(k);
?????????????//定義研發部門下的結構
?????????????developDep.add(firstDevGroup);
?????????????developDep.add(secondDevGroup);
?????????????//研發部經理下還有一個副總
?????????????developDep.add(zhengLaoLiu);
?????????????//看看開發兩個開發小組下有什么
?????????????firstDevGroup.add(a);
?????????????firstDevGroup.add(b);
?????????????firstDevGroup.add(c);
?????????????secondDevGroup.add(d);
?????????????secondDevGroup.add(e);
?????????????secondDevGroup.add(f);
?????????????//再看銷售部下的人員情況
?????????????salesDep.add(h);
?????????????salesDep.add(i);
?????????????//最后一個財務
?????????????financeDep.add(j);
?????????????//打印寫完的樹狀結構
?????????????System.out.println(ceo.getInfo());
?????????????//打印出來整個樹形
?????????????getAllSubordinateInfo(ceo.getSubordinateInfo());
?????}
?????//遍歷所有的樹枝節點,打印出信息
?????private?static?void?getAllSubordinateInfo(ArrayList?subordinateList){
?????????????int?length?=?subordinateList.size();
?????????????//定義一個ArrayList長度,不要在for循環中每次計算
?????????????for(int?m=0;m<length;m++){??
??????????????????Object?s?=?subordinateList.get(m);
??????????????????if(s?instanceof?Leaf){??//是個葉子節點,也就是員工
??????????????????????????ILeaf?employee?=?(ILeaf)s;
??????????????????????????System.out.println(((Leaf)?s).getInfo());
??????????????????}else{
??????????????????????????IBranch?branch?=?(IBranch)s;
??????????????????????????System.out.println(branch.getInfo());
??????????????????????????//再遞歸調用
??????????????????????????getAllSubordinateInfo(branch.getSubordinateInfo());
??????????????????}
?????????????}
?????}
}
這個程序比較長,如果在我們的項目中有這樣的程序,肯定是要被拉出來做典型的,你寫一大坨的程序給誰呀,以后還要維護,程序要短小精悍!幸運的是,我們這是作為案例來講解,而且就是指出這樣組裝這棵樹是有問題的,等會我們深入講解,先看運行結果:
?
| 名稱:王大麻子 | 職位:總經理 | 薪水: 100000 |
|-----|-----|-----|
| 名稱:劉大瘸子 | 職位:研發部門經理 | 薪水:10000 |
| 名稱:楊三乜斜 | 職位:開發一組組長 | 薪水:5000 |
| 名稱:a | 職位:開發人員 | 薪水:2000 |
| 名稱:b | 職位:開發人員 | 薪水:2000 |
| 名稱:c | 職位:開發人員 | 薪水:2000 |
| 名稱:吳大棒槌 | 職位:開發二組組長 | 薪水:6000 |
| 名稱:d | 職位:開發人員 | 薪水:2000 |
| 名稱:e | 職位:開發人員 | 薪水:2000 |
| 名稱:f | 職位:開發人員 | 薪水:2000 |
| 名稱:鄭老六 | 職位:研發部副總 | 薪水:20000 |
| 名稱:馬二拐子 | 職位:銷售部門經理 | 薪水:20000 |
| 名稱:h | 職位:銷售人員 | 薪水:5000 |
| 名稱:i | 職位:銷售人員 | 薪水:4000 |
| 名稱:趙三駝子 | 職位:財務部經理 | 薪水:30000 |
| 名稱:j | 職位:財務人員 | 薪水:5000 |
| 名稱:k | 職位:CEO秘書 | 薪水:8000 |
和我們期望的結果一樣,一棵完整的樹就生成了,而且我們還能夠遍歷。不錯,不錯,但是看類圖或程序的時候,你有沒有發覺有問題?getInfo每個接口都有,為什么不能抽象出來?Root類和Branch類有什么差別?根節點本身就是樹枝節點的一種,為什么要定義成兩個接口兩個類?如果我要加一個任職期限,你是不是每個類都需要修改?如果我要后序遍歷(從員工找到他的上級領導)能做到嗎?——徹底暈菜了!
問題很多,我們一個一個解決,先說抽象的問題。我們確實可以把IBranch和IRoot合并成一個接口,確認無疑的事我們先做,那我們就修改一下類圖,如圖21-3所示。
仔細看看這個類圖,還能不能發現點問題。想想看接口的作用是什么?定義一類事物所具有的共性,那ILeaf和IBranch是不是也有共性呢?有,getInfo方法!我們是不是要把這個共性也封裝起來呢?是的,是的,提煉事物的共同點,然后封裝之,這是我們作為設計專家的拿手好戲,修改后的類圖如圖21-4所示。

圖21-3 整合根節點和樹枝節點后的類圖

圖21-4 修改后的類圖
類圖上增加了一個ICorp接口,它是公司所有人員信息的接口類,不管你是經理還是員工,你都有名字、職位、薪水,這個定義成一個接口沒有錯,但是你可能對于ILeaf接口持懷疑狀態,空接口有何意義呀?有意義!它是每個樹枝節點的代表,系統擴容的時候你就會發現它是多么“棟梁”。我們先來看新增加的接口ICorp,如代碼清單21-8所示。
代碼清單21-8 公司人員接口
public?interface?ICorp?{
?????//每個員工都有信息,你想隱藏,門兒都沒有!
?????public?String?getInfo();
}
接口很簡單,只有一個方法,就是獲得員工的信息,樹葉節點是最基層的構件,我們先來看看它的接口,空接口,如代碼清單21-9所示。
代碼清單21-9 樹葉接口
public?interface?ILeaf?extends?ICorp?{
}
樹葉接口的實現類,如代碼清單21-10所示。
代碼清單21-10 樹葉接口
public?class?Leaf?implements?ILeaf?{
?????//小兵也有名稱
?????private?String?name?=?"";
?????//小兵也有職位
?????private?String?position?=?"";
?????//小兵也有薪水,否則誰給你干
?????private?int?salary?=?0;
?????//通過一個構造函數傳遞小兵的信息
?????public?Leaf(String?name,String?position,int?salary){
?????????????this.name?=?name;
?????????????this.position?=?position;
?????????????this.salary?=?salary;
?????}
?????//獲得小兵的信息
?????public?String?getInfo()?{
?????????????String?info?=?"";
?????????????info?=?"姓名:"?+?this.name;
?????????????info?=?info?+?"\t職位:"+?this.position;
?????????????info?=?info?+?"\t薪水:"?+?this.salary;
?????????????return?info;
?????}
}
小兵就只有這些信息了,我們是具體干活的,我們是管理不了其他同事的,我們來看看那些經理和小組長是怎么實現的,也就是IBranch接口,如代碼清單21-11所示。
代碼清單21-11 樹枝接口
public?interface?IBranch?extends?ICorp?{?????
?????//能夠增加小兵(樹葉節點)或者是經理(樹枝節點)
?????public?void?addSubordinate(ICorp?corp);
?????//我還要能夠獲得下屬的信息
?????public?ArrayList<ICorp>?getSubordinate();
?????/*本來還應該有一個方法delSubordinate(ICorp?corp),刪除下屬
??????*?這個方法我們沒有用到就不寫進來了
??????*/
}
接口也很簡單,其實現類也不可能太復雜,如代碼清單21-12所示。
代碼清單21-12 樹枝實現類
public?class?Branch?implements?IBranch?{
?????//領導也是人,也有名字
?????private?String?name?=?"";
?????//領導和領導不同,也是職位區別
?????private?String?position?=?"";
?????//領導也是拿薪水的
?????private?int?salary?=?0;
?????//領導下邊有哪些下級領導和小兵
?????ArrayList<ICorp>?subordinateList?=?new?ArrayList<ICorp>();
?????//通過構造函數傳遞領導的信息
?????public?Branch(String?name,String?position,int?salary){
?????????????this.name?=?name;
?????????????this.position?=?position;
?????????????this.salary?=?salary;
?????}
?????//增加一個下屬,可能是小頭目,也可能是個小兵
?????public?void?addSubordinate(ICorp?corp)?{
?????????????this.subordinateList.add(corp);
?????}
?????//我有哪些下屬
?????public?ArrayList<ICorp>?getSubordinate()?{
?????????????return?this.subordinateList;
?????}
?????//領導也是人,他也有信息
?????public?String?getInfo()?{
?????????????String?info?=?"";
?????????????info?=?"姓名:"?+?this.name;
?????????????info?=?info?+?"\t職位:"+?this.position;
?????????????info?=?info?+?"\t薪水:"?+?this.salary;
?????????????return?info;
?????}
}
實現類也很簡單,不多說,程序寫得好不好,就看別人怎么調用了,我們看場景類Client,如代碼清單21-13所示。
代碼清單21-13 場景類a
public?class?Client?{
?????public?static?void?main(String[]?args)?{
?????????????//首先是組裝一個組織結構出來
?????????????Branch?ceo?=?compositeCorpTree();
?????????????//首先把CEO的信息打印出來
?????????????System.out.println(ceo.getInfo());
?????????????//然后是所有員工信息
?????????????System.out.println(getTreeInfo(ceo));
?????}
?????//把整個樹組裝出來
?????public?static?Branch?compositeCorpTree(){
?????????????//首先產生總經理CEO
?????????????Branch?root?=?new?Branch("王大麻子","總經理",100000);
?????????????//把三個部門經理產生出來
?????????????Branch?developDep?=?new?Branch("劉大瘸子","研發部門經理",10000);
?????????????Branch?salesDep?=?new?Branch("馬二拐子","銷售部門經理",20000);
?????????????Branch?financeDep?=?new?Branch("趙三駝子","財務部經理",30000);
?????????????//再把三個小組長產生出來
?????????????Branch?firstDevGroup?=?new?Branch("楊三乜斜","開發一組組長",5000);
?????????????Branch?secondDevGroup?=?new?Branch("吳大棒槌","開發二組組長",6000);
?????????????//把所有的小兵都產生出來
?????????????Leaf?a?=?new?Leaf("a","開發人員",2000);
?????????????Leaf?b?=?new?Leaf("b","開發人員",2000);
?????????????Leaf?c?=?new?Leaf("c","開發人員",2000);
?????????????Leaf?d?=?new?Leaf("d","開發人員",2000);
?????????????Leaf?e?=?new?Leaf("e","開發人員",2000);
?????????????Leaf?f?=?new?Leaf("f","開發人員",2000);
?????????????Leaf?g?=?new?Leaf("g","開發人員",2000);
?????????????Leaf?h?=?new?Leaf("h","銷售人員",5000);
?????????????Leaf?i?=?new?Leaf("i","銷售人員",4000);
?????????????Leaf?j?=?new?Leaf("j","財務人員",5000);
?????????????Leaf?k?=?new?Leaf("k","CEO秘書",8000);
?????????????Leaf?zhengLaoLiu?=?new?Leaf("鄭老六","研發部副經理",20000);
?????????????//開始組裝
?????????????//CEO下有三個部門經理和一個秘書
?????????????root.addSubordinate(k);
?????????????root.addSubordinate(developDep);
?????????????root.addSubordinate(salesDep);
?????????????root.addSubordinate(financeDep);
?????????????//研發部經理
?????????????developDep.addSubordinate(zhengLaoLiu);
?????????????developDep.addSubordinate(firstDevGroup);
?????????????developDep.addSubordinate(secondDevGroup);
?????????????//看看兩個開發小組下有什么
?????????????firstDevGroup.addSubordinate(a);
?????????????firstDevGroup.addSubordinate(b);
?????????????firstDevGroup.addSubordinate(c);
?????????????secondDevGroup.addSubordinate(d);
?????????????secondDevGroup.addSubordinate(e);
?????????????secondDevGroup.addSubordinate(f);
?????????????//再看銷售部下的人員情況
?????????????salesDep.addSubordinate(h);
?????????????salesDep.addSubordinate(i);
?????????????//最后一個財務
?????????????financeDep.addSubordinate(j);
?????????????return?root;
?????}
?????//遍歷整棵樹,只要給我根節點,我就能遍歷出所有的節點
?????public?static?String?getTreeInfo(Branch?root){
?????????????ArrayList<ICorp>?subordinateList?=?root.getSubordinate();
?????????????String?info?=?"";
?????????????for(ICorp?s?:subordinateList){
?????????????????????if(s?instanceof?Leaf){?//是員工就直接獲得信息
?????????????????????????????info?=?info?+?s.getInfo()+"\n";
?????????????????????}else{?//是個小頭目
?????????????????????????????info?=?info?+?s.getInfo()?+"\n"+?getTreeInfo((Branch)s);
?????????????????????}
?????????????}
?????????????return?info;
?????}
}
運行結果完全相同,不再贅述。通過這樣構件,一個非常清晰的樹狀人員資源管理圖出現了,那我們的程序是否還可以優化?可以!你看Leaf和Branch中都有getInfo信息,是不是可以抽象?好,我們抽象一下,如圖21-5所示。

圖21-5 精簡的類圖
你一看這個圖,樂了。能不樂嘛,減少很多工作量了,接口沒有了,改成抽象類了,IBranch接口也沒有了,直接把方法放到了實現類中了,太精簡了!而且場景類只認定抽象類Corp就成,那我們首先來看抽象類ICorp,如代碼清單21-14所示。
代碼清單21-14 抽象公司職員類
public?abstract?class?Corp?{
?????//公司每個人都有名稱
?????private?String?name?=?"";
?????//公司每個人都職位
?????private?String?position?=?"";
?????//公司每個人都有薪水
?????private?int?salary?=0;?????
?????public?Corp(String?_name,String?_position,int?_salary){
?????????????this.name?=?_name;
?????????????this.position?=?_position;
?????????????this.salary?=?_salary;
?????}
?????//獲得員工信息
?????public?String?getInfo(){
?????????????String?info?=?"";
?????????????info?=?"姓名:"?+?this.name;
?????????????info?=?info?+?"\t職位:"+?this.position;
?????????????info?=?info?+?"\t薪水:"?+?this.salary;
?????????????return?info;
?????}
}
抽象類嘛,就應該抽象出一些共性的東西出來,然后看兩個具體的實現類,樹葉節點如代碼清單21-15所示。
代碼清單21-15 樹葉節點
public?class?Leaf?extends?Corp?{
?????//就寫一個構造函數,這個是必需的
?????public?Leaf(String?_name,String?_position,int?_salary){
?????????????super(_name,_position,_salary);
?????}
}
這個精簡得比較多,幾行代碼就完成了,確實就應該這樣,下面是小頭目的實現類,如代碼清單21-16所示。
代碼清單21-16 樹枝節點
public?class?Branch?extends?Corp?{
?????//領導下邊有哪些下級領導和小兵
?????ArrayList<Corp>?subordinateList?=?new?ArrayList<Corp>();
?????//構造函數是必需的
?????public?Branch(String?_name,String?_position,int?_salary){
?????????????super(_name,_position,_salary);
?????}
?????//增加一個下屬,可能是小頭目,也可能是個小兵
?????public?void?addSubordinate(Corp?corp)?{
?????????????this.subordinateList.add(corp);
?????}
?????//我有哪些下屬
?????public?ArrayList<Corp>?getSubordinate()?{
?????????????return?this.subordinateList;
?????}
}
場景類中構建樹形結構,并進行遍歷。組裝沒有變化,遍歷組織機構數稍有變化,如代碼清單21-17所示。
代碼清單21-17 稍稍修改的場景類
public?class?Client?{
?????//遍歷整棵樹,只要給我根節點,我就能遍歷出所有的節點
?????public?static?String?getTreeInfo(Branch?root){
?????????????ArrayList<Corp>?subordinateList?=?root.getSubordinate();
?????????????String?info?=?"";
?????????????for(Corp?s?:subordinateList){
????????????????????if(s?instanceof?Leaf){?//是員工就直接獲得信息
???????????????????????????info?=?info?+?s.getInfo()+"\n";
????????????????????}else{?//是個小頭目
???????????????????????????info?=?info+s.getInfo()+"\n"+?getTreeInfo((Branch)s);
????????????????????}
?????????????}
?????????????return?info;
?????}
}
場景類中main方法沒有變動,請參考代碼清單21-7所示,不再贅述。遍歷組織機構樹的getTreeInfo稍有修改,就是把用到ICorp接口的地方修改為Corp抽象類,僅僅修改了粗體部分,其他保持不變,運行結果相同。這就是組合模式。
- 前言
- 第一部分 大旗不揮,誰敢沖鋒——6大設計原則全新解讀
- 第1章 單一職責原則
- 1.2 絕殺技,打破你的傳統思維
- 1.3 我單純,所以我快樂
- 1.4 最佳實踐
- 第2章 里氏替換原則
- 2.2 糾紛不斷,規則壓制
- 2.3 最佳實踐
- 第3章 依賴倒置原則
- 3.2 言而無信,你太需要契約
- 3.3 依賴的三種寫法
- 3.4 最佳實踐
- 第4章 接口隔離原則
- 4.2 美女何其多,觀點各不同
- 4.3 保證接口的純潔性
- 4.4 最佳實踐
- 第5章 迪米特法則
- 5.2 我的知識你知道得越少越好
- 5.3 最佳實踐
- 第6章 開閉原則
- 6.2 開閉原則的廬山真面目
- 6.3 為什么要采用開閉原則
- 6.4 如何使用開閉原則
- 6.5 最佳實踐
- 第二部分 真刀實槍 ——23種設計模式完美演繹
- 第7章 單例模式
- 7.2 單例模式的定義
- 7.3 單例模式的應用
- 7.4 單例模式的擴展
- 7.5 最佳實踐
- 第8章 工廠方法模式
- 8.2 工廠方法模式的定義
- 8.3 工廠方法模式的應用
- 8.4 工廠方法模式的擴展
- 8.5 最佳實踐
- 第9章 抽象工廠模式
- 9.2 抽象工廠模式的定義
- 9.3 抽象工廠模式的應用
- 9.4 最佳實踐
- 第10章 模板方法模式
- 10.2 模板方法模式的定義
- 10.3 模板方法模式的應用
- 10.4 模板方法模式的擴展
- 10.5 最佳實踐
- 第11章 建造者模式
- 11.2 建造者模式的定義
- 11.3 建造者模式的應用
- 11.4 建造者模式的擴展
- 11.5 最佳實踐
- 第12章 代理模式
- 12.2 代理模式的定義
- 12.3 代理模式的應用
- 12.4 代理模式的擴展
- 12.5 最佳實踐
- 第13章 原型模式
- 13.2 原型模式的定義
- 13.3 原型模式的應用
- 13.4 原型模式的注意事項
- 13.5 最佳實踐
- 第14章 中介者模式
- 14.2 中介者模式的定義
- 14.3 中介者模式的應用
- 14.4 中介者模式的實際應用
- 14.5 最佳實踐
- 第15章 命令模式
- 15.2 命令模式的定義
- 15.3 命令模式的應用
- 15.4 命令模式的擴展
- 15.5 最佳實踐
- 第16章 責任鏈模式
- 16.2 責任鏈模式的定義
- 16.3 責任鏈模式的應用
- 16.4 最佳實踐
- 第17章 裝飾模式
- 17.2 裝飾模式的定義
- 17.3 裝飾模式應用
- 17.4 最佳實踐
- 第18章 策略模式
- 18.2 策略模式的定義
- 18.3 策略模式的應用
- 18.4 策略模式的擴展
- 18.5 最佳實踐
- 第19章 適配器模式
- 19.2 適配器模式的定義
- 19.3 適配器模式的應用
- 19.4 適配器模式的擴展
- 19.5 最佳實踐
- 第20章 迭代器模式
- 20.2 迭代器模式的定義
- 20.3 迭代器模式的應用
- 20.4 最佳實踐
- 第21章 組合模式
- 21.2 組合模式的定義
- 21.3 組合模式的應用
- 21.4 組合模式的擴展
- 21.5 最佳實踐
- 第22章 觀察者模式
- 22.2 觀察者模式的定義
- 22.3 觀察者模式的應用
- 22.4 觀察者模式的擴展
- 22.5 最佳實踐
- 第23章 門面模式
- 23.2 門面模式的定義
- 23.3 門面模式的應用
- 23.4 門面模式的注意事項
- 23.5 最佳實踐
- 第24章 備忘錄模式
- 24.2 備忘錄模式的定義
- 24.3 備忘錄模式的應用
- 24.4 備忘錄模式的擴展
- 24.5 最佳實踐
- 第25章 訪問者模式
- 25.2 訪問者模式的定義
- 25.3 訪問者模式的應用
- 25.4 訪問者模式的擴展
- 25.5 最佳實踐
- 第26章 狀態模式
- 26.2 狀態模式的定義
- 26.3 狀態模式的應用
- 第27章 解釋器模式
- 27.2 解釋器模式的定義
- 27.3 解釋器模式的應用
- 27.4 最佳實踐
- 第28章 享元模式
- 28.2 享元模式的定義
- 28.3 享元模式的應用
- 28.4 享元模式的擴展
- 28.5 最佳實踐
- 第29章 橋梁模式
- 29.2 橋梁模式的定義
- 29.3 橋梁模式的應用
- 29.4 最佳實踐
- 第三部分 誰的地盤誰做主 ——設計模式PK
- 第30章 創建類模式大PK
- 30.1 工廠方法模式VS建造者模式
- 30.2 抽象工廠模式VS建造者模式
- 第31章 結構類模式大PK
- 31.1 代理模式VS裝飾模式
- 31.2 裝飾模式VS適配器模式
- 第32章 行為類模式大PK
- 32.1 命令模式VS策略模式
- 32.2 策略模式VS狀態模式
- 32.3 觀察者模式VS責任鏈模式
- 第33章 跨戰區PK
- 33.1 策略模式VS橋梁模式
- 33.2 門面模式VS中介者模式
- 33.3 包裝模式群PK
- 第四部分 完美世界 ——設計模式混編
- 第34章 命令模式+責任鏈模式
- 34.2 混編小結
- 第35章 工廠方法模式+策略模式
- 35.2 混編小結
- 第36章 觀察者模式+中介者模式
- 36.2 混編小結
- 第五部分 擴展篇
- 第37章 MVC框架
- 37.2 最佳實踐
- 第38章 新模式
- 38.1 規格模式
- 38.2 對象池模式
- 38.3 雇工模式
- 38.4 黑板模式
- 38.5 空對象模式
- 附錄 23種設計模式彩圖