参考文档:http://blog.csdn.net/ai92/article/details/298336

定义:

组合多个对象形成树形结构以表示“整体-部分”的结构层次。

设计动机:

这幅图片我们都可以看做是一个文件结构,对于这样的结构我们称之为树形结构。在数据结构中我们了解到可以通过调用某个方法来遍历整个树,当我们找到某个叶子节点后,就可以对叶子节点进行相关的操作。我们可以将这颗树理解成一个大的容器,容器里面包含很多的成员对象,这些成员对象即可是容器对象也可以是叶子对象。但是由于容器对象和叶子对象在功能上面的区别,使得我们在使用的过程中必须要区分容器对象和叶子对象,但是这样就会给客户带来不必要的麻烦,作为客户而已,它始终希望能够一致的对待容器对象和叶子对象。这就是组合模式的设计动机:组合模式定义了如何将容器对象和叶子对象进行递归组合,使得客户在使用的过程中无须进行区分,可以对他们进行一致的处理。

模式实现:

  • Component:抽象构件角色。它为组合中的对象声明接口,也可以为共有接口实现缺省行为
  • Leaf:树叶构件角色。在组合中表示叶节点对象——没有子节点,实现抽象构件角色声明的接口。

  • Composite:树枝构件角色。在组合中表示分支节点对象——有子节点,实现抽象构件角色声明的接口;存储子部件。

一种方式是在Component里面声明所有的用来管理子类对象的方法,以达到Component接口的最大化(如下图所示)。目的就是为了使客户看来在接口层次上树叶和分支没有区别——透明性。但树叶是不存在子类的,因此Component声明的一些方法对于树叶来说是不适用的。这样也就带来了一些安全性问题。



另一种方式就是只在Composite里面声明所有的用来管理子类对象的方法(如下图所示)。这样就避免了上一种方式的安全性问题,但是由于叶子和分支有不同的接口,所以又失去了透明性。

《设计模式》一书认为:在这一模式中,相对于安全性,我们比较强调透明性。对于第一种方式中叶子节点内不需要的方法可以使用空处理或者异常报告的方式来解决。

优点:

1、可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件也更容易。

2、客户端调用简单,客户端可以一致的使用组合结构或其中单个对象。

3、定义了包含叶子对象和容器对象的类层次结构,叶子对象可以被组合成更复杂的容器对象,而这个容器对象又可以被组合,这样不断递归下去,可以形成复杂的树形结构。

4、更容易在组合体内加入对象构件,客户端不必因为加入了新的对象构件而更改原有代码。

举个栗子:

定义抽象角色

abstract class File{
public abstract void addChild(File f);
public abstract void delChild(File f);
public abstract void scan();
}

定义叶子实现

class ImgFile extends File{
@Override
public void addChild(File f) {
}
@Override
public void delChild(File f) {
}
@Override
public void scan() {
System.out.println("im an img");
}
}

定义叶子实现

    class VideoFile extends File{
@Override
public void addChild(File f) {
}
@Override
public void delChild(File f) {
}
@Override
public void scan() {
System.out.println("im a video");
}
}

定义树枝实现

    class Folder extends File{
List<File> files=new ArrayList<File>();
@Override
public void addChild(File f) {
files.add(f);
}
@Override
public void delChild(File f) {
files.remove(f);
}
@Override
public void scan() {
System.out.println("im folder,i have some files :");
for (File f : files) {
f.scan();
}
}
}

客户端调用

    public static void main(String[] args) {
File c=new Folder();
File windows=new Folder();
windows.addChild(new ImgFile());
c.addChild(windows);
c.scan();
}

最新文章

  1. 简单谈谈NFC(转载自-tlex/pku_android)
  2. Palindrome Number
  3. 使用GridVIew显示Gantt(甘特图),动态增减列
  4. C# 自定义FileUpload控件
  5. VC 宏与预处理使用方法总结
  6. 正则化,数据集扩增,Dropout
  7. Python开发者最常犯的10个错误
  8. hdu 2444 The Accomodation of Students(最大匹配 + 二分图判断)
  9. 【实习记】2014-09-26恢复linux下误删的ntfs盘中的文件
  10. LeeCode(Database)-Duplicate Emails
  11. github上前100的ios项目
  12. 爬虫实践---悦音台mv排行榜与简单反爬虫技术应用
  13. 凡事预则立(Beta)
  14. qq浏览器默认字体设置
  15. Pycharm使⽤用秘笈v0.3PyCharm使⽤用秘籍
  16. 解题:USACO14OPEN Fair Photography
  17. 使用Spring Security和OAuth2实现RESTful服务安全认证
  18. linux下增加useradd提示existing lock file /etc/subgid.lock without a PID
  19. thinkphp 的 Action 控制器中的系统常量总结
  20. 自定义map对象,用于再不支持es6的map的时候

热门文章

  1. 【转载】C#使用InsertRange方法往ArrayList集合指定位置插入另一个集合
  2. Kubernetes学习之原理
  3. nginx 日志整理 目录区分 日志配置
  4. workman即时推送
  5. IDEA集成jacoco
  6. K-th Path CodeForces - 1196F
  7. web api .net C# mvc API返回XML文档的解析并取值
  8. Graylog-centos安装
  9. Elasticsearch 索引文档如何使用自动生成 Id?
  10. git 学习笔记 —— 获取远端分支并修改后提交至远端仓库