合成(composite)模式

  合成模式属于对象的结构模式,有时又叫做“部分——整体”模式。合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式可以使客户端将单纯元素与复合元素同等看待。

合成模式

  合成模式把部分和整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由它们复合而成的合成对象同等看待。比如,一个文件系统就是一个典型的合成模式系统。下图是常见的计算机XP文件系统的一部分。

  从上图可以看出,文件系统是一个树结构,树上长有节点。树的节点有两种,一种是树枝节点,即目录,有内部树结构,在图中涂有颜色;另一种是文件,即树叶节点,没有内部树结构。显然,可以把目录和文件当做同一种对象同等对待和处理,这也就是合成模式的应用。合成模式可以不提供父对象的管理方法,但是合成模式必须在合适的地方提供子对象的管理方法,诸如:add()、remove()、以及getChild()等。合成模式的实现根据所实现接口的区别分为两种形式,分别称为安全式和透明式

安全式合成模式的结构

  安全模式的合成模式要求管理聚集的方法只出现在树枝构件类中,而不出现在树叶构件类中。

  这种形式涉及到三个角色:

  • 抽象构件(Component)角色:这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认为,可以用来管理所有的子对象。合成对象通常把它所包含的子对象当做类型为Component的对象。在安全式的合成模式里,构件角色并不定义出管理子对象的方法,这一定义由树枝构件对象给出。
  • 树叶构件(Leaf)角色:树叶对象是没有下级子对象的对象,定义出参加组合的原始对象的行为。
  • 树枝构件(Composite)角色:代表参加组合的有下级子对象的对象。树枝构件类给出所有的管理子对象的方法,如add()、remove()以及getChild()。

源代码

// @类说明 :抽象构件角色类
public interface Component {
  public void printStruct(String preStr); /  /  输出组建自身的名称
}   

//@类说明 :树枝构件角色类
public class Composite implements Component {
    // 用来存储组合对象中包含的子组件对象
    private List<Component> childComponents = new ArrayList<Component>();
    //组合对象的名字
    private String name;
    public Composite(String name) {
        this.name = name;
    }
    public void addChild(Component child) {
        childComponents.add(child);
    }
    public void removeChild(int index) {
        childComponents.remove(index);
    }
    public List<Component> getChild() {
        return childComponents;
    }
    @Override
    public void printStruct(String preStr) {
            System.out.println(preStr + "+" + this.name);
            if(this.childComponents != null) {
                preStr += "  ";
               for (Component c : childComponents) {
                      c.printStruct(preStr);
               }
            }
    }
}  

//@类说明 :树叶构件角色类
public class Leaf implements Component {
    private String name;  // 叶子对象的名字
    public Leaf(String name) {
        this.name = name;
    }
    //输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字
     @Override
    public void printStruct(String preStr) {
        System.out.println(preStr + "-" + name);
    }
}  

//@类说明 :客户端类
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.addChild(c1);
        root.addChild(c2);
        c1.addChild(leaf1);
        c1.addChild(leaf2);
        c2.addChild(leaf3);
        c2.addChild(leaf4);
        root.printStruct("");
    }
}  

  可以看出,树枝构件类(Composite)给出了addChild()、removeChild()以及getChild()等方法的声明和实现,而树叶构件类则没有给出这些方法的声明或实现。这样的做法是安全的做法,由于这个特点,客户端应用程序不可能错误地调用树叶构件的聚集方法,因为树叶构件没有这些方法,调用会导致编译错误。

  安全式合成模式的缺点是不够透明,因为树叶类和树枝类将具有不同的接口。

透明式合成模式的结构

  与安全式的合成模式不同的是,透明式的合成模式要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定接口。

源代码

抽象构件角色类

//@类说明 :抽象构件角色类
public abstract class Component {
      public abstract void printStruct(String preStr);  //   输出组建自身的名称
      public void addChild(Component child) {
             throw new UnsupportedOperationException("对象不支持此功能");
      }
      public void removeChild(int index) {
             throw new UnsupportedOperationException("对象不支持此功能");
      }
      public List<Component> getChild() {
            throw new UnsupportedOperationException("对象不支持此功能");
       }
}  

//@类说明 :树枝构件角色类,此类将implements Conponent改为extends Conponent,其他地方无变化。
public class Composite extends Component {
    private List<Component> childComponents = new ArrayList<Component>();  / / 用来存储组合对象中包含的子组件对象
    private String name;  /  /  组合对象的名字
    public Composite(String name) {
        this.name = name;
    }
    public void addChild(Component child) {
        childComponents.add(child);
    }
    public void removeChild(int index) {
        childComponents.remove(index);
    }
     public List<Component> getChild() {
        return childComponents;
     }
    @Override
     public void printStruct(String preStr) {
        // 先把自己输出
        System.out.println(preStr + "+" + this.name);
        // 如果还包含有子组件,那么就输出这些子组件对象
        if (this.childComponents != null) {
            // 添加两个空格,表示向后缩进两个空格
            preStr += "  ";
            // 输出当前对象的子对象
            for (Component c : childComponents) {
                // 递归输出每个子对象
                c.printStruct(preStr);
            }
        }
    }
}  

// @类说明 :树叶构件角色类,此类将implements Conponent改为extends Conponent,其他地方无变化。
public class Leaf extends Component {
   private String name;    //   输出组建自身的名称
   public Leaf(String name) {
        this.name = name;
    }
   @Override
   public void printStruct(String preStr) {
        // TODO Auto-generated method stub
        System.out.println(preStr + "-" + name);
    }
}  

//客户端类的主要变化是不再区分Composite对象和Leaf对象。
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("");
    }
}  

  可以看出,客户端无需再区分操作的是树枝对象(Composite)还是树叶对象(Leaf)了;对于客户端而言,操作的都是Component对象。

两种实现方法的选择

  这里所说的安全性合成模式是指:从客户端使用合成模式上看是否更安全,如果是安全的,那么就不会有发生误操作的可能,能访问的方法都是被支持的。

  这里所说的透明性合成模式是指:从客户端使用合成模式上,是否需要区分到底是“树枝对象”还是“树叶对象”。如果是透明的,那就不用区分,对于客户而言,都是Compoent对象,具体的类型对于客户端而言是透明的,是无须关心的。

  对于合成模式而言,在安全性和透明性上,会更看重透明性,毕竟合成模式的目的是:让客户端不再区分操作的是树枝对象还是树叶对象,而是以一个统一的方式来操作。而且对于安全性的实现,需要区分是树枝对象还是树叶对象。有时候,需要将对象进行类型转换,却发现类型信息丢失了,只好强行转换,这种类型转换必然是不够安全的。因此在使用合成模式的时候,建议多采用透明性的实现方式。

时间: 2024-10-03 23:28:35

合成(composite)模式的相关文章

C++设计模式实现--组合(Composite)模式

一. 举例 这个例子是书上的,假设有一个公司的组结结构如下: 它的结构很像一棵树,其中人力资源部和财务部是没有子结点的,具体公司才有子结点. 而且最关健的是,它的每一层结构很相似. 代码实现如下: #include <iostream> #include <list> #include <string> using namespace std; //公司类,提供接口 class Company { public: Company(string name) { m_nam

Java组合模式(Composite模式)

Composite定义:将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性. Composite比较容易理解,想到Composite就应该想到树形结构图.组合体内这些对象都有共同接口,当组合体一个对象的方法被调用执行时,Composite将遍历(Iterator)整个树形结构,寻找同样包含这个方法的对象并实现调用执行.可以用牵一动百来形容. 所以Composite模式使用到Iterator模式,和Chain of Responsibilit

Java 实现组合(Composite)模式

类图 /** * 树 整体 * * @author stone * */ public class Tree { private TreeNode root; //根节点 public Tree(String name) { this.root = new TreeNode(name); } public TreeNode getRoot() { return root; } } /** * 树节点 部份 * 也可以自身代表树:一堆节点组成了一颗树 * * @author stone * */

Android与设计模式——组合(Composite)模式

定义(GoF<设计模式>):将对象组合成树形结构以表示"部分整体"的层次结构.组合模式使得用户对单个对象和组合对象的使用具有一致性.  涉及角色 1.Component:(View)是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为.声明一个接口用于访问和管理Component子部件. 2.Leaf:(TextView.自定义View)在组合中表示叶子结点对象,叶子结点没有子结点(即不能在View内再添加View). 3.Composite:(ViewGr

Composite模式 组合模式

Android的ViewGroup 和 View 的关系,即是采用组合模式 1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 我们可以使用简单的对象组合成复杂的对象,而这个复杂对象有可以组合成更大的对象.我们可以把简单这些对象定义成类,然后定义一些容器类来存储这些简单对象.客户端代码必须区别对象简单对象和容器对象,而实际上大多数情况下用户认为它们是一样的.对这些类区别使用,使得程序更加复杂.递归使用

Composite模式

在开发时,如果遇到使用递归构建树状的组合结构,那么可以考虑使用Composite模式.Composite模式将对象组合成树形结构,来表示部分.整体的层次结构. 其类结构如图所示: 在Component中声明了所有管理子类对象的方法,因此实现Component接口的子类都有了Add.Remove等功能,这样叶子节点和枝节点对于外界没有区别:但是因为Leaf类本身不具备Add.Remove等功能,实现也没有意义. 在实现时,管理叶子节点需要容器,这里使用了vector. //Component.h

Structual设计--Composite模式

1.意图 将对象组合成树形结构以表示"部分-整体"的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 2.别名 无 3.动机 在绘图编辑器和图形捕捉系统这样的图形应用程序中,用户可以使用简单的组件创建复杂的图表.用户可以组合多个简单组件以形成一些较大的组件,这些组件又可以组合成更大的组件.一个简单的实现方法是为Text和Line这样的图元定义一些类,另外定义一些类作为这些图元的容器类(Container). 然而存在一个问题:使用这些类的代码必需区别对待图元对

二十三种设计模式之:组合(Composite)模式(部分&#183;整体模式)

组合(Composite)模式又叫部分·整体模式,主要用于实现树形结构. 例子如下: public class TreeNode{ private TreeNode parent; private String name; private List<TreeNode> children = new Arraylist<TreeNode>(); public TreeNode(String name){ this.name = name; } public String getNam

设计模式:Composite模式

设计模式:组合(Composite)模式 一.前言   关于Composite模式,其实就是组合模式,又叫部分整体模式,这个模式在我们的生活中也经常使用,比如说如果读者有使用Java的GUI编写过程序的,肯定少不了定义一些组件,初始化之后,然后使用容器的add方法,将这些组件有顺序的组织成一个界面出来:或者读者如果编写过前端的页面,肯定使用过<div>等标签定义一些格式,然后格式之间互相组合,通过一种递归的方式组织成相应的结构.这种方式其实就是组合,将部分的组件镶嵌到整体之中.那么凭什么可以这