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. 使程序能够引入.json文件, 为网站添加 MIME 映射

    确认启用了 MIME 映射,或使用命令行工具 appcmd.exe 为网站添加 MIME 映射. 若要设置 MIME 类型,请在 IIS Express 安装目录中运行以下命令: appcmd set ...

  2. mysql sql语句分析

    1. SELECT     a.id    ,b.order_id,b.attr  FROM    tourist_order a     LEFT JOIN order_attr b     ON ...

  3. 【转载】Java StringBuffer与StringBuider

    本文转载微学苑java基础教程,原文地址链接:http://www.weixueyuan.net/view/6318.html String 的值是不可变的,每次对String的操作都会生成新的Str ...

  4. 详解boost库中的Message Queue .

    Message Queue(后文简写成MQ或消息队列)是boost库中用来封装进程间通信的一种实现,同一台机器上的进程或线程可以通过消息队列来进行通迅.消息队列中的消息由优先级.消息长度.消息数据三部 ...

  5. uva 12207 - That is Your Queue

    #include <cstdio> #include <iostream> #include <deque> using namespace std; int ma ...

  6. java动态缓存技术:WEB缓存应用(转)

    可以实现不等待,线程自动更新缓存 Java动态缓存jar包请下载. 源代码: CacheData.java 存放缓存数据的Bean /** *  */package com.cari.web.cach ...

  7. javaScript的select元素和option的相关操作

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. Nginx常用Rewrite伪静态法则

    信赖此刻大部门用Linux VPS的伴侣都在利用这个敏捷传布的Nginx,本日就清算一下最常见的PHP法式的Rewrite(伪静态法则). Wordpress: location / {index i ...

  9. c# windows 服务学习

    用C#做windows服务变得简单对了===按照下面步骤来就行了 用C#创建Windows服务(Windows Services)例子服务功能:这个服务在启动和停止时,向一个文本文件中写入一些文字信息 ...

  10. Java编程之字符集问题研究

    1. 概述 本文主要包括以下几个方面:编码基本知识,java,系统软件,url,工具软件等. 在下面的描述中,将以"中文"两个字为例,经查表可以知道其GB2312编码是" ...