設計模式16—設計模式之組合模式(Composite)(結構型)

來源:互聯網
上載者:User
1.情境類比

使用軟體類比大樹的根節點和樹枝節點和葉子節點
抽象為兩類,容器節點和葉子節點
2.不用模式的解決方案

package demo14.composite.example1;import java.util.*;/** * 組合對象,可以包含其它組合對象或者葉子物件 */public class Composite {/** * 用來記錄包含的其它組合對象 */private Collection<Composite> childComposite = new ArrayList<Composite>();/** * 用來記錄包含的其它葉子物件 */private Collection<Leaf> childLeaf = new ArrayList<Leaf>();/** * 組合對象的名字 */private String name = "";/** * 構造方法,傳入組合對象的名字 * @param name 組合對象的名字 */public Composite(String name){this.name = name;}/** * 向組合對象加入被它包含的其它組合對象 * @param c 被它包含的其它組合對象 */public void addComposite(Composite c){this.childComposite.add(c);}/** * 向組合對象加入被它包含的葉子物件 * @param leaf 被它包含的葉子物件 */public void addLeaf(Leaf leaf){this.childLeaf.add(leaf);}/** * 輸出組合對象自身的結構 * @param preStr 首碼,主要是按照層級拼接的空格,實現向後縮排 */public void printStruct(String preStr){//先把自己輸出去System.out.println(preStr+"+"+this.name);//然後添加一個空格,表示向後縮排一個空格,輸出自己包含的葉子物件preStr+=" ";for(Leaf leaf : childLeaf){leaf.printStruct(preStr);}//輸出當前對象的子物件了for(Composite c : childComposite){//遞迴輸出每個子物件c.printStruct(preStr);}}}***********************************************************************************************package demo14.composite.example1;/** * 葉子物件 */public class Leaf {/** * 葉子物件的名字 */private String name = "";/** * 構造方法,傳入葉子物件的名字 * @param name 葉子物件的名字 */public Leaf(String name){this.name = name;}/** * 輸出葉子物件的結構,葉子物件沒有子物件,也就是輸出葉子物件的名字 * @param preStr 首碼,主要是按照層級拼接的空格,實現向後縮排 */public void printStruct(String preStr){System.out.println(preStr+"-"+name);}}***************************************************************************************************package demo14.composite.example1;public class Client {public static void main(String[] args) {// 定義所有的組合對象Composite root = new Composite("服裝");Composite c1 = new Composite("男裝");Composite c2 = new Composite("女裝");// 定義所有的葉子物件Leaf leaf1 = new Leaf("襯衣");Leaf leaf2 = new Leaf("夾克");Leaf leaf3 = new Leaf("裙子");Leaf leaf4 = new Leaf("套裝");// 按照樹的結構來組合組合對象和葉子物件root.addComposite(c1);root.addComposite(c2);c1.addLeaf(leaf1);c1.addLeaf(leaf2);c2.addLeaf(leaf3);c2.addLeaf(leaf4);// 調用根對象的輸出功能來輸出整棵樹root.printStruct("");}}
3.問題所在

大家很容易就發現了一個問題:那就是必須區分葉子節點和容器節點,無論是用戶端還是內部都要區分,那麼這樣就會使得程式變得複雜,對於功能的擴充也不方便,而且要知道兩個類才行,那麼我們能不能把他整合成一個類呢,讓用戶端如下顯示呢?答案是可以的。

package demo14.composite.example2;public class Client {public static void main(String[] args) {//定義多個Composite對象Component root = new Composite();Component c1 = new Composite();Component c2 = new Composite();//定義多個葉子物件Component leaf1 = new Leaf();Component leaf2 = new Leaf();Component leaf3 = new Leaf();//組和成為樹形的對象結構root.addChild(c1);root.addChild(c2);root.addChild(leaf1);c1.addChild(leaf2);c2.addChild(leaf3);//操作Component對象Component o = root.getChildren(1);System.out.println(o);}}
4.解決方案的範例程式碼

很明顯,上述用戶端的代碼就順眼多了,那麼我們改如何?呢?
4.1首先看結構圖

 
4.2組合模式定義

將對象組合成樹形結構以表示“部分-整體”的階層。組合模式使得使用者對單個對象和組合對象的使用具有一致性。
4.3範例程式碼如下

package demo14.composite.example2;/** * 抽象的組件對象,為組合中的對象聲明介面,實現介面的預設行為 */public abstract class Component {/** * 示意方法,子組件對象可能有的功能方法 */public abstract void someOperation();/** * 向組合對象中加入組件對象 *  * @param child *        被加入組合對象中的組件對象 */public void addChild(Component child) {// 預設的實現,拋出例外,因為葉子物件沒有這個功能,或者子組件沒有實現這個功能throw new UnsupportedOperationException("對象不支援這個功能");}/** * 從組合對象中移出某個組件對象 *  * @param child *        被移出的組件對象 */public void removeChild(Component child) {// 預設的實現,拋出例外,因為葉子物件沒有這個功能,或者子組件沒有實現這個功能throw new UnsupportedOperationException("對象不支援這個功能");}/** * 返回某個索引對應的組件對象 *  * @param index *        需要擷取的組件對象的索引,索引從0開始 * @return 索引對應的組件對象 */public Component getChildren(int index) {// 預設的實現,拋出例外,因為葉子物件沒有這個功能,或者子組件沒有實現這個功能throw new UnsupportedOperationException("對象不支援這個功能");}}**********************************************************************package demo14.composite.example2;import java.util.*;/** * 組合對象,通常需要儲存子物件,定義有子組件的組件行為, * 並實現在Component裡面定義的與子組件有關的操作 */public class Composite extends Component {/** * 用來儲存群組合對象中包含子群組件對象 */private List<Component> childComponents = null;/** * 示意方法,通常在裡面需要實現遞迴的調用 */public void someOperation() {if (childComponents != null){for(Component c : childComponents){//遞迴的進行子組件相應方法的調用c.someOperation();}}}public void addChild(Component child) {//延遲初始化if (childComponents == null) {childComponents = new ArrayList<Component>();}childComponents.add(child);}public void removeChild(Component child) {if (childComponents != null) {childComponents.remove(child);}}public Component getChildren(int index) {if (childComponents != null){if(index>=0 && index<childComponents.size()){return childComponents.get(index);}}return null;}}**********************************************************************package demo14.composite.example2;/** * 葉子物件,葉子物件不再包含其它子物件 */public class Leaf extends Component {/** * 示意方法,葉子物件可能有自己的功能方法 */public void someOperation() {// do something}}**********************************************************************package demo14.composite.example2;public class Client {public static void main(String[] args) {//定義多個Composite對象Component root = new Composite();Component c1 = new Composite();Component c2 = new Composite();//定義多個葉子物件Component leaf1 = new Leaf();Component leaf2 = new Leaf();Component leaf3 = new Leaf();//組和成為樹形的對象結構root.addChild(c1);root.addChild(c2);root.addChild(leaf1);c1.addChild(leaf2);c2.addChild(leaf3);//操作Component對象Component o = root.getChildren(1);System.out.println(o);}}
5.組合模式解決情境類比

代碼的修改量並不大,跟範例程式碼差不多
5.1結構圖如下

 
5.2代碼如下(基本上同範例程式碼差不多,就不過多介紹了,注釋非常清楚)

package demo14.composite.example3;/** * 抽象的組件對象 */public abstract class Component {/** * 輸出組件自身的名稱 */public abstract void printStruct(String preStr);/** * 向組合對象中加入組件對象 *  * @param child *        被加入組合對象中的組件對象 */public void addChild(Component child) {// 預設的實現,拋出例外,因為葉子物件沒有這個功能,或者子組件沒有實現這個功能throw new UnsupportedOperationException("對象不支援這個功能");}/** * 從組合對象中移出某個組件對象 *  * @param child *        被移出的組件對象 */public void removeChild(Component child) {// 預設的實現,拋出例外,因為葉子物件沒有這個功能,或者子組件沒有實現這個功能throw new UnsupportedOperationException("對象不支援這個功能");}/** * 返回某個索引對應的組件對象 *  * @param index *        需要擷取的組件對象的索引,索引從0開始 * @return 索引對應的組件對象 */public Component getChildren(int index) {// 預設的實現,拋出例外,因為葉子物件沒有這個功能,或者子組件沒有實現這個功能throw new UnsupportedOperationException("對象不支援這個功能");}}*********************************************************************************************package demo14.composite.example3;import java.util.*;/** * 組合對象,可以包含其它組合對象或者葉子物件 */public class Composite extends Component{/** * 用來儲存群組合對象中包含子群組件對象 */private List<Component> childComponents = null;/** * 組合對象的名字 */private String name = "";/** * 構造方法,傳入組合對象的名字 * @param name 組合對象的名字 */public Composite(String name){this.name = name;}public void addChild(Component child) {//延遲初始化if (childComponents == null) {childComponents = new ArrayList<Component>();}childComponents.add(child);}/** * 輸出組合對象自身的結構 * @param preStr 首碼,主要是按照層級拼接的空格,實現向後縮排 */public void printStruct(String preStr){//先把自己輸出去System.out.println(preStr+"+"+this.name);//如果還包含有子組件,那麼就輸出這些子組件對象if(this.childComponents!=null){//然後添加一個空格,表示向後縮排一個空格preStr+=" ";//輸出當前對象的子物件了for(Component c : childComponents){//遞迴輸出每個子物件c.printStruct(preStr);}}}}**********************************************************************************************package demo14.composite.example3;/** * 葉子物件 */public class Leaf extends Component {/** * 葉子物件的名字 */private String name = "";/** * 構造方法,傳入葉子物件的名字 *  * @param name *        葉子物件的名字 */public Leaf(String name) {this.name = name;}/** * 輸出葉子物件的結構,葉子物件沒有子物件,也就是輸出葉子物件的名字 *  * @param preStr *        首碼,主要是按照層級拼接的空格,實現向後縮排 */public void printStruct(String preStr) {System.out.println(preStr + "-" + name);}}********************************************************************************************package demo14.composite.example3;public class Client {public static void main(String[] args) {//定義所有的組合對象Component root = new Composite("服裝");Component c1 = new Composite("男裝");Component c2 = new Composite("女裝");//定義所有的葉子物件Component leaf1 = new Leaf("襯衣");Component leaf2 = new Leaf("夾克");Component leaf3 = new Leaf("裙子");Component leaf4 = new Leaf("套裝");//按照樹的結構來組合組合對象和葉子物件root.addChild(c1);root.addChild(c2);c1.addChild(leaf1);c1.addChild(leaf2);c2.addChild(leaf3);c2.addChild(leaf4);//調用根對象的輸出功能來輸出整棵樹root.printStruct("");}}
6.組合模式講解6.1要點

目的:用戶端不再區分葉子節點和組合對象
關鍵點:設計一個抽象的組合對象
6.2組合模式本質

統一葉子物件和組合對象

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.