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. jQuery 基本实现功能模板

    下面是列出了基本功能的实现 <!DOCTYPE html> <html> <head> <script src="http://libs.baidu ...

  2. mongodb查询只显示指定字段

    db.COMMODITY_COMMODITY.find( { "areaCode" : "320100" , "backCatalogId" ...

  3. 保障MySQL安全的14个最佳方法

    MySQL数据库一贯以高性能.高可性和易用性著称,它已经成为世界上最流行的开源数据库.大量的个人.WEB开发者.大型公司等都在其网站.关键系统.软件包中广泛使用MySQL数据库.        通常, ...

  4. JavaScript Arguments 实现可变参数的函数,以及函数的递归调用

    //可变参数的函数 注:也可以使用对象作为参数来实现 function Max() { var temp = arguments[0] || 0; for (var i = 1; i < arg ...

  5. C# linq的学习及使用

    linq可以对多种数据源和对象进行查询,如数据库.数据集.XML文档.数组等. 通过对linq的使用,可以减少代码量并优化检索操作. LINQ关键字 from 指定数据源和范围变量 where 根据布 ...

  6. UEFI模式下安装Win 7系统

    转载自:http://huayi898.blog.163.com/blog/static/2581351620144442319155/ 下载win7_64bit原版官方系统 1.用软碟通制作U盘启动 ...

  7. LR:Code - 60990,Code - 10343 问题解决

    Code - 60990 Error: Two Way Communication Error: Function two_way_comm_post_message /two_way_comm_po ...

  8. YOU邮件

    include("class.phpmailer.php");include("class.smtp.php");//获取一个外部文件的内容$mail      ...

  9. javascript之闭包深入理解(一)

    曾经在开始学习javascript的时候,很是不理解闭包的概念.今天想对它详细的剖析. 在说清楚闭包之前,必须先清楚作用域链. 作用域链 我们知道,执行环境是js中最为重要的一个概念.执行环境定义了变 ...

  10. Poweroff – 很好很强大的定制关机工具

    Poweroff – 很好很强大的定制关机工具 Poweroff 是一个用来管理电脑关机系统的小工具,支持定时,支持远程 作者开放源代码,有兴趣的同学可以尝试着制作一下汉化版本.   可以设定不同时间 ...