Java 設計模式系列(九)組合模式

來源:互聯網
上載者:User

標籤:外部   用戶端   site   component   管理   something   etc   索引   分享圖片   

Java 設計模式系列(九)組合模式

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

一、組合模式結構

  • Component: 抽象的組件對象,為組合中的對象聲明介面,讓用戶端可以通過這個介面來訪問和管理整個對象結構,可以在裡面為定義的功能提供預設的實現。

  • Leaf: 葉子節點對象,定義和實現葉子物件的行為,不再包含其它的子節點對象。

  • Composite: 組合對象,通常會儲存子組件,定義包含子組件的那些組件的行為,並實現在組件介面中定義的與子組件有關的操作。

  • Client: 用戶端,通過組件介面來操作組合結構裡面的組件對象。

組合模式參考實現

(1)先看看組件對象的定義,範例程式碼如下:

/** * 抽象的組件對象,為組合中的對象聲明介面,實現介面的預設行為 */public abstract class Component {    /** 示意方法,子組件對象可能有的功能方法 */    public abstract void someOperation();    /** 向組合對象中加入組件對象 */    public void addChild(Component child) {        // 預設的實現,拋出例外,因為葉子物件沒有這個功能,或者子組件沒有實現這個功能        throw new UnsupportedOperationException("對象不支援這個功能");    }    /** 從組合對象中移出某個組件對象 */    public void removeChild(Component child) {        // 預設的實現,拋出例外,因為葉子物件沒有這個功能,或者子組件沒有實現這個功能        throw new UnsupportedOperationException("對象不支援這個功能");    }    /** 返回某個索引對應的組件對象 */    public Component getChildren(int index) {        // 預設的實現,拋出例外,因為葉子物件沒有這個功能,或者子組件沒有實現這個功能        throw new UnsupportedOperationException("對象不支援這個功能");    }}

(2)接下來看看Composite對象的定義,範例程式碼如下:

/** * 組合對象,通常需要儲存子物件,定義有子組件的組件行為, * 並實現在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;    }}

(3)該來看葉子物件的定義了,相對而言比較簡單,範例程式碼如下:

/** * 葉子物件,葉子物件不再包含其它子物件 */public class Leaf extends Component {    /** 示意方法,葉子物件可能有自己的功能方法 */    public void someOperation() {        // do something    }}

(4)對於Client,就是使用Component介面來操作組合對象結構,由於使用方式千差萬別,這裡僅僅提供一個示範性質的使用,順便當作測試代碼使用,範例程式碼如下:

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);    }}
二、父組件引用

(1) Component

public abstract class Component {    /**     * 記錄父組件對象     */    private Component parent = null;    /**     * 擷取一個組件的父組件對象     * @return 一個組件的父組件對象     */    public Component getParent() {        return parent;    }    /**     * 設定一個組件的父組件對象     * @param parent 一個組件的父組件對象     */    public void setParent(Component parent) {        this.parent = parent;    }    /**     * 返回某個組件的子組件對象     * @return 某個組件的子組件對象     */    public List<Component> getChildren() {        throw new UnsupportedOperationException("對象不支援這個功能");    }    /*-------------------以下是原有的定義----------------------*/    /**     * 輸出組件自身的名稱     */    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("對象不支援這個功能");    }}

(2) Leaf

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);    }}

(3) Composite

public class Composite extends Component{    public void addChild(Component child) {        //延遲初始化        if (childComponents == null) {            childComponents = new ArrayList<Component>();        }        childComponents.add(child);        //添加對父組件的引用        child.setParent(this);    }    public void removeChild(Component child) {        if (childComponents != null) {            //尋找到要刪除的組件在集合中的索引位置            int idx = childComponents.indexOf(child);            if (idx != -1) {                //先把被刪除的商品類別對象的父商品類別,設定成為被刪除的商品類別的子類別的父商品類別                for(Component c : child.getChildren()){                    //刪除的組件對象是本執行個體的一個子組件對象                    c.setParent(this);                    //把被刪除的商品類別對象的子組件對象添加到當前執行個體中                    childComponents.add(c);                }                //真的刪除                childComponents.remove(idx);            }        }    }    public List<Component> getChildren() {        return childComponents;    }    /*-------------------以下是原有的實現,沒有變化----------------------*/    /**     * 用來儲存群組合對象中包含子群組件對象     */    private List<Component> childComponents = null;    /**     * 組合對象的名字     */    private String name = "";    /**     * 構造方法,傳入組合對象的名字     * @param name 組合對象的名字     */    public Composite(String name){        this.name = name;    }    /**     * 輸出組合對象自身的結構     * @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);            }        }    }}
三、總結(1) 觀察者模式的本質

組合模式的本質: 統一葉子物件和組合對象。

組合模式通過把葉子物件當成特殊的組合對象看待,從而對葉子物件和組合對象一視同仁,統統當成了Component對象,有機的統一了葉子物件和組合對象。

正是因為統一了葉子物件和組合對象,在將對象構建成樹形結構的時候,才不需要做區分,反正是組件對象裡麵包含其它的組件對象,如此遞迴下去;也才使得對於樹形結構的操作變得簡單,不管物件類型,統一操作。

(2) 何時選用觀察者模式
  • 如果你想表示對象的部分-整體階層,可以選用組合模式,把整體和部分的操作統一起來,使得階層實現更簡單,從外部來使用這個階層也簡單。

  • 如果你希望統一的使用組合結構中的所有對象,可以選用組合模式,這正是組合模式提供的主要功能。

(3) 觀察者模式的優缺點
  • 定義了包含基本對象和組合對象的類階層

    在組合模式中,基本對象可以被組合成更複雜的組合對象,而組合對象又可以組合成更複雜的組合對象,可以不斷地遞迴組合下去,從而構成一個統一的組合對象的類階層

  • 統一了組合對象和葉子物件

    在組合模式中,可以把葉子物件當作特殊的組合對象看待,為它們定義統一的父類,從而把組合對象和葉子物件的行為統一起來

  • 簡化了用戶端調用

    組合模式通過統一組合對象和葉子物件,使得用戶端在使用它們的時候,就不需要再去區分它們,客戶不關心使用的到底是什麼類型的對象,這就大大簡化了用戶端的使用

  • 更容易擴充

    由於用戶端是統一的面對Component來操作,因此,新定義的Composite或Leaf子類能夠很容易的與已有的結構一起工作,而用戶端不需要為增添了新的組件類而改變

  • 很難限制組合中的組件類型

    容易增加新的組件也會帶來一些問題,比如很難限制組合中的組件類型。這在需要檢測組件類型的時候,使得我們不能依靠編譯期的類型約束來完成,必須在運行期間動態檢測。

每天用心記錄一點點。內容也許不重要,但習慣很重要!

Java 設計模式系列(九)組合模式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.