1.场景模拟

使用软件模拟大树的根节点和树枝节点和叶子节点
抽象为两类,容器节点和叶子节点

2.不用模式的解决方案

package demo14.composite.example1;
import java.util.*; /**
* 组合对象,可以包含其它组合对象或者叶子对象
*/
public class Composite {
/**
* 用来记录包含的其它组合对象
*/
private Collection<Composite> childComposite = new ArrayList<Composite>();
/**
* 用来记录包含的其它叶子对象
*/
private Collection<Leaf> childLeaf = new ArrayList<Leaf>();
/**
* 组合对象的名字
*/
private String name = "";
/**
* 构造方法,传入组合对象的名字
* @param name 组合对象的名字
*/
public Composite(String name){
this.name = name;
}
/**
* 向组合对象加入被它包含的其它组合对象
* @param c 被它包含的其它组合对象
*/
public void addComposite(Composite c){
this.childComposite.add(c);
}
/**
* 向组合对象加入被它包含的叶子对象
* @param leaf 被它包含的叶子对象
*/
public void addLeaf(Leaf leaf){
this.childLeaf.add(leaf);
}
/**
* 输出组合对象自身的结构
* @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进
*/
public void printStruct(String preStr){
//先把自己输出去
System.out.println(preStr+"+"+this.name);
//然后添加一个空格,表示向后缩进一个空格,输出自己包含的叶子对象
preStr+=" ";
for(Leaf leaf : childLeaf){
leaf.printStruct(preStr);
}
//输出当前对象的子对象了
for(Composite c : childComposite){
//递归输出每个子对象
c.printStruct(preStr);
}
}
}
***********************************************************************************************
package demo14.composite.example1;
/**
* 叶子对象
*/
public class Leaf {
/**
* 叶子对象的名字
*/
private String name = "";
/**
* 构造方法,传入叶子对象的名字
* @param name 叶子对象的名字
*/
public Leaf(String name){
this.name = name;
}
/**
* 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字
* @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进
*/
public void printStruct(String preStr){
System.out.println(preStr+"-"+name);
}
}
***************************************************************************************************
package demo14.composite.example1; 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.addComposite(c1);
root.addComposite(c2); c1.addLeaf(leaf1);
c1.addLeaf(leaf2); c2.addLeaf(leaf3);
c2.addLeaf(leaf4); // 调用根对象的输出功能来输出整棵树
root.printStruct("");
}
}

3.问题所在

大家很容易就发现了一个问题:那就是必须区分叶子节点和容器节点,无论是客户端还是内部都要区分,那么这样就会使得程序变得复杂,对于功能的扩展也不方便,而且要知道两个类才行,那么我们能不能把他整合成一个类呢,让客户端如下显示呢?答案是可以的。

package demo14.composite.example2;

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

4.解决方案的示例代码

很明显,上述客户端的代码就顺眼多了,那么我们改如何实现呢?

4.1首先看结构图

4.2组合模式定义

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

4.3示例代码如下

package demo14.composite.example2;

/**
* 抽象的组件对象,为组合中的对象声明接口,实现接口的缺省行为
*/
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("对象不支持这个功能");
}
}
**********************************************************************
package demo14.composite.example2; import java.util.*; /**
* 组合对象,通常需要存储子对象,定义有子部件的部件行为,
* 并实现在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;
}
}
**********************************************************************
package demo14.composite.example2; /**
* 叶子对象,叶子对象不再包含其它子对象
*/
public class Leaf extends Component {
/**
* 示意方法,叶子对象可能有自己的功能方法
*/
public void someOperation() {
// do something
}
}
**********************************************************************
package demo14.composite.example2; 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);
}
}

5.组合模式解决场景模拟

代码的修改量并不大,跟示例代码差不多

5.1结构图如下

5.2代码如下(基本上同示例代码差不多,就不过多介绍了,注释非常清楚)

package demo14.composite.example3;

/**
* 抽象的组件对象
*/
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("对象不支持这个功能");
}
}
*********************************************************************************************
package demo14.composite.example3;
import java.util.*; /**
* 组合对象,可以包含其它组合对象或者叶子对象
*/
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);
}
}
}
}
**********************************************************************************************
package demo14.composite.example3; /**
* 叶子对象
*/
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);
}
}
********************************************************************************************
package demo14.composite.example3; 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("");
}
}

6.组合模式讲解

6.1要点

目的:客户端不再区分叶子节点和组合对象
关键点:设计一个抽象的组合对象

6.2组合模式本质

统一叶子对象和组合对象

设计模式16---设计模式之组合模式(Composite)(行为型)的更多相关文章

  1. 设计模式(七)组合模式Composite(结构型)

    设计模式(七)组合模式Composite(结构型) 1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 ...

  2. 设计模式(八)组合模式 Composite

    组合模式: 允许你将对象组合成树形结构来表现“整体/部分”层次结构.组合能让客户以一致的方式处理个别对象以及对象组合. 组合模式适用于创建复杂的对象,这个对象包含某些个别的对象以及这些对象的组合. 从 ...

  3. Headfirst设计模式的C++实现——组合模式(Composite)

    menu_component.h #ifndef _MENU_COMPONENT_H_ #define _MENU_COMPONENT_H_ #include <string> class ...

  4. Java设计模式(8)组合模式(Composite模式)

    Composite定义:将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性. Composite比较容易理解,想到Composite就应该想到树 ...

  5. 乐在其中设计模式(C#) - 组合模式(Composite Pattern)

    原文:乐在其中设计模式(C#) - 组合模式(Composite Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 组合模式(Composite Pattern) 作者:weba ...

  6. 设计模式系列之组合模式(Composite Pattern)——树形结构的处理

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  7. 浅谈设计模式--组合模式(Composite Pattern)

    组合模式(Composite Pattern) 组合模式,有时候又叫部分-整体结构(part-whole hierarchy),使得用户对单个对象和对一组对象的使用具有一致性.简单来说,就是可以像使用 ...

  8. 二十四种设计模式:组合模式(Composite Pattern)

    组合模式(Composite Pattern) 介绍将对象组合成树形结构以表示"部分-整体"的层次结构.它使得客户对单个对象和复合对象的使用具有一致性.示例有一个Message实体 ...

  9. 【设计模式】组合模式 Composite Pattern

    树形结构是软件行业很常见的一种结构,几乎随处可见,  比如: HTML 页面中的DOM,产品的分类,通常一些应用或网站的菜单,Windows Form 中的控件继承关系,Android中的View继承 ...

  10. 设计模式 - 组合模式(composite pattern) 迭代器(iterator) 具体解释

    组合模式(composite pattern) 迭代器(iterator) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考组合模式(composit ...

随机推荐

  1. 为什么不使用frame框架的原因

    框架的优点 重载页面时不需要重载整个页面,只需要重载页面中的一个框架页(减少了数据的传输,增加了网页下载速度) 方便制作导航栏 框架的缺点 会产生很多页面,不容易管理 不容易打印 浏览器的后退按钮无效 ...

  2. SQL 查询字段为值不为空

      方法一sql="select   *   from   table   where   id<>null   "     or   sql="select ...

  3. jQuery入门必须掌握的一些API

    jQuery 中文版文档:http://www.css88.com/jqapi-1.9/category/ajax/ jQuery入门,必须掌握以下的API,平时工作中经常会用到.未列出的API,在掌 ...

  4. office - 连接字符串.

    Microsoft ACE OLEDB 12.0 Connect to Excel 2007 (and later) files with the Xlsx file extension. That ...

  5. linux RedHat 5 更新vim.

    概述: 想装 ctags,装不上.看到老外有篇日志,是在vi 7.2版本上运行.怕是vi版本的原因,于是想升级,网上升级的方法写得少,有的写的太无语了,只有他自己看得懂.这里,简单说下.搞半天了,终于 ...

  6. iOS 网络与多线程--7.Performselector消息处理方法

    创建一个IOSApp类 IOSApp.h文件 #import <Foundation/Foundation.h> @interface IOSApp : NSObject // 1.添加一 ...

  7. C#操作Excel文件(转)

    摘要:本文介绍了Excel对象.C#中的受管代码和非受管代码,并介绍了COM组件在.net环境中的使用. 关键词:受管代码:非受管代码:Excel对象:动态连接库 引言 Excel是微软公司办公自动化 ...

  8. Thinkphp 连接数据库、查询、添加

    一.连接数据库配置及Model数据模型层 1. Thinkphp\conf\convertion.php中找到数据库设置部分,复制到自己的配置文件中,并添加好有关数据库的内容 JiaoWu\Home\ ...

  9. 推荐IOS开发3个工具:Homebrew、TestFight、Crashlytics-备

    1. Homebrew 什么是Homebrew? Homebrew is the easiest and most flexible way to install the UNIX tools App ...

  10. Android利用百度地图定位

    百度地图照着百度的教程做的总是出现报错 请帮我看看错误在那 2013-12-13 15:16168海军 | 分类:百度地图 | 浏览1252次 java.lang.RuntimeException: ...