组合模式

定义:

  将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。

   也称为 整体-部分(Part-Whole)模式,它的宗旨是通过将单个对象(叶子节点)和组合对象(树枝节点)用相同的接口进行表示,使得客户对单个对象和组合对象的使用具有一致性。

  

其中根节点 和 树枝节点 本质上是同一种数据类型,可以作为容器使用;而 叶子节点 与 树枝节点 在语义上不属于同一种类型,但是在 组合模式 中,会把 树枝节点 和 叶子节点 认为是同一种数据类型(用同一接口定义),让它们具备一致行为。这样,在 组合模式中,整个树形结构中的对象都是同一种类型,带来的一个好处就是客户无需辨别 树枝节点 还是 叶子节点,而是可以直接进行操作,给客户使用带来极大的便利。

结构图: 

 

 

 

 组合模式分为透明方式和安全方式,区别就是在Component基类中是否声明所有接口:

  透明方式:在Component中声明所有用来管理子类的方法;坏处是对于叶子对象来说有些接口是没有意义的。好处是客户端不需要做相应的判断;

  安全模式;在Component只声明系统各个层次的最基础的一致行为,而把有用来管理子类的方法放到Composite当中;坏处是由于树枝和叶子类不具有相同的接口,客户端调用时需要做相应的判断。好处是叶子对象不需要实现多余的方法。

 

代码(创建文件夹目录系统,包含组合对象:文件夹和单个对象:文件):(安全模式

 //抽象根类:Component,只定义最基础行为:Display

class Directory

{

protected:

   String name;

public:

   Directory(String name)

  {

     this.name = name;

  }

  void Display() = 0;

}

 

//树枝节点:Composite
class Folder : Directory

{
private:

   List<Directory> mDirs;

 

public:

   Folder(String name)

   {
    this.name = name;
       this.mDirs = new ArrayList<>();
  }

  void Display()

  {
    System.out.println(this.name + “: Folder”);
    foreach ( Directory in mDirs)

     {
      Directory.Display();
    }
  }

//树枝节点中新增自己的管理方法

 

  void addDir(Directory dir)

  {
    return this.mDirs.add(dir);
  }

 

  void removeDir(Directory dir)

  {
    return this.mDirs.remove(dir);
  }

}
//叶子节点:Leaf
class File : Directory

{

 

public:

   File(String name)

  {

    this.name = name;
  }

 

  void Display()

  {
    System.out.println(this.name + “: file”);
  }
}

 

//客户端 (对于客户端来说文件和文件夹的display没有区别,文件夹和文件的区别只是否有增删接口而已,在透明模式中,甚至不需要客户端知道区别)

Folder A = new Folder(“A”);//创建文件夹A

File Ax = new File(“Ax”);//创建文件Ax

File Ay = new File(“Ay”);//创建文件Ay

A.addDir(Ax);//添加文件Ax
A.addDir(Ax);//添加文件Ay
A.Display();

 

使用时机:

  系统对象层次具备整体和部分,呈树形结构,且要求具备统一行为,以及希望客户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时(如树形菜单,操作系统目录结构,公司组织架构等);

 

优点:

1、组合模式可以让用户一致的使用组合结构(树枝)和单个对象(树叶)。

2、可以很方便地增加 树枝节点 和 叶子节点 对象,并对现有类库无侵入,符合 开闭原则

 

缺点:如果类系统(树形结构)过于庞大,虽然对不同层次都提供一致性操作,但客户端仍需花费时间理清类之间的层次关系;