`
chjavach
  • 浏览: 460957 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

研磨设计模式 之 组合模式(Composite) 2——跟着cc学设计系列

 
阅读更多

15.2  解决方案

15.2.1  组合模式来解决

用来解决上述问题的一个合理的解决方案就是组合模式。那么什么是组合模式呢?

(1)组合模式定义

 

(2)应用组合模式来解决的思路

       仔细分析上面不用模式的例子中,要区分组合对象和叶子对象的根本原因,就在于没有把组合对象和叶子对象统一起来,也就是说,组合对象类型和叶子对象类型是完全不同的类型,这导致了操作的时候必须区分它们。

       组合模式通过引入一个抽象的组件对象,作为组合对象和叶子对象的父对象,这样就把组合对象和叶子对象统一起来了,用户使用的时候,始终是在操作组件对象,而不再去区分是在操作组合对象还是在操作叶子对象。

组合模式的关键就在于这个抽象类,这个抽象类既可以代表叶子对象,也可以代表组合对象,这样用户在操作的时候,对单个对象和组合对象的使用就具有了一致性。

15.2.2  模式结构和说明

组合模式的结构如图15.1所示:

 

图15.1  组合模式结构示意图

Component

       抽象的组件对象,为组合中的对象声明接口,让客户端可以通过这个接口来访问和管理整个对象结构,可以在里面为定义的功能提供缺省的实现。

Leaf

       叶子节点对象,定义和实现叶子对象的行为,不再包含其它的子节点对象。

Composite

       组合对象,通常会存储子组件,定义包含子组件的那些组件的行为,并实现在组件接口中定义的与子组件有关的操作。

Client

       客户端,通过组件接口来操作组合结构里面的组件对象。

 

       一种典型的Composite对象结构通常是如图15.2所示的树形结构,一个Composite对象可以包含多个叶子多象和其它的Composite对象,虽然15.2的图看起来好像有些对称,但是那只是为了让图看起来美观一点,并不是说Composite组合的对象结构就是这样对称的,这点要提前说明一下。

 

图15.2  典型的Composite对象结构

15.2.3  组合模式的示例代码

(1)先看看组件对象的定义,示例代码如下:

/**

 * 抽象的组件对象,为组合中的对象声明接口,实现接口的缺省行为

 */

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(

"对象不支持这个功能");

    }

}

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

    }

}

15.2.4  使用组合模式重写示例

理解了组合模式的定义、结构和示例代码过后,对组合模式应该有一定的掌握了,下面就来使用组合模式,来重写前面不用模式的示例,看看用组合模式来实现会是什么样子,跟不用模式有什么相同和不同之处。

为了整体理解和把握整个示例,先来看看示例的整体结构,如图15.3所示:

 

图15.3  使用组合模式实现示例的结构示意图

(1)首先就是要为组合对象和叶子对象添加一个抽象的父对象做为组件对象,在组件对象里面,定义一个输出组件本身名称的方法以实现要求的功能,示例代码如下:

/**

 * 抽象的组件对象

 */

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(

"对象不支持这个功能");

    }

}

(2)先看叶子对象的实现,它变化比较少,只是让叶子对象继承了组件对象,其它的跟不用模式比较,没有什么变化,示例代码如下:

/**

 * 叶子对象

 */

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对象需要继承组件对象
  • 原来用来记录包含的其它组合对象的集合,和包含的其它叶子对象的集合,这两个集合被合并成为一个,就是统一的包含其它子组件对象的集合。使用组合模式来实现,不再需要区分到底是组合对象还是叶子对象了
  • 原来的addComposite和addLeaf的方法,可以不需要了,合并实现成组件对象中定义的方法addChild,当然需要现在的Composite来实现这个方法。使用组合模式来实现,不再需要区分到底是组合对象还是叶子对象了
  • 原来的printStruct方法的实现,完全要按照现在的方式来写,变化较大

具体的示例代码如下:

/**

 * 组合对象,可以包含其它组合对象或者叶子对象

 */

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

           }

       }

    }

}

(4)客户端也有变化,客户端不再需要区分组合对象和叶子对象了,统一都是使用组件对象,调用的方法也都要改变成组件对象定义的方法。示例代码如下:

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("");

    }

}

       通过上面的示例,大家可以看出,通过使用组合模式,把一个“部分-整体”的层次结构表示成了对象树的结构,这样一来,客户端就无需再区分操作的是组合对象还是叶子对象了,对于客户端而言,操作的都是组件对象。

---------------------------------------------------------------------------

私塾在线学习网原创内容  跟着cc学设计系列 之 研磨设计模式

研磨设计讨论群【252780326】

原创内容,转载请注明出处【http://sishuok.com/forum/blogPost/list/0/5512.html

---------------------------------------------------------------------------

4
7
分享到:
评论

相关推荐

    研磨设计模式(完整带书签).part2.pdf

    第15章 组合模式(Composite) 第16章 模板方法模式(Template Method) 第17章 策略模式(Strategy) 第18章 状态模式(State) 第19章 备忘录模式(Memento) 第20章 享元模式(Flyweight) 第21章 解释器模式...

    研磨设计模式源码

    研磨设计模式的配套源码,请下载,不要想了,解压后,直接放到eclipse下面即可运行!

    研磨设计模式带书签完整版228M.7z.001

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式 完美书签 完整(一)

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式带书签完整版228M.7z.002

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式-陈臣.epub

    “1.1 设计模式是什么 1.1.1 什么是模式 从字面上理解,模,就是模型、模板的意思;式,就是方式、方法的意思。综合起来,所谓模式就是:可以作为模型或模板的方式或方法。... “研磨设计模式”。 iBooks.

    研磨设计模式PDF

    研磨设计模式PDF

    研磨设计模式(完整带书签).part1.pdf

    第15章 组合模式(Composite) 第16章 模板方法模式(Template Method) 第17章 策略模式(Strategy) 第18章 状态模式(State) 第19章 备忘录模式(Memento) 第20章 享元模式(Flyweight) 第21章 解释器模式...

    研磨设计模式视频课程PPT

    内容概述:本视频课程是北京Java私塾原创精品书籍《研磨设计模式》一书的配套学习视频,由《研磨设计模式》的第一作者CC录制 课程目标:全面、系统的掌握GoF设计模式的知识,达到可以在实际项目开发中运用的能力 ...

    研磨设计模式(完整版pdf)part2 (2-3)

    研磨设计模式(完整版pdf)相信我不用介绍,很多人都在找这本书吧,今天我特意从另外的地方下载到了这本书,发了几十积分。才弄到。为了让大家同时分享这本书的精华。我今天特意上传。注:此电子书较大,我分了3个...

    研磨设计模式高清完整版(2)

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式-陈臣.王斌.扫描高清版PDF

    设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。 使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;...

    研磨设计模式(完整版pdf) part1 (1-3)

    研磨设计模式(完整版pdf)相信我不用介绍,很多人都在找这本书吧,今天我特意从另外的地方下载到了这本书,发了几十积分。才弄到。为了让大家同时分享这本书的精华。我今天特意上传。注:此电子书较大,我分了3个...

    研磨设计模式.part2

    研磨设计模式.part2 一定要下载5部分

    研磨设计模式带书签完整版228M.7z.003

    研磨设计模式《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地...

    研磨设计模式书-配套源代码(全)

    0该书是《研磨设计模式》,只有前几张,网上完整版电子书还没有,这是本人收集的最完备的,最多的前几章。 1:本源代码是《研磨设计模式》一书的配套源代码 2:每个模式的示例源代码放在一个单独的文件夹下,以该...

    研磨设计模式-陈臣pdf

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式高清完整版(1)

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式 PDF ZIP.001(三个压缩包)

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式-陈臣.mobi kindle版

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

Global site tag (gtag.js) - Google Analytics