设计模式16---设计模式之组合模式(Composite)(行为型)
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)(行为型)的更多相关文章
- 设计模式(七)组合模式Composite(结构型)
设计模式(七)组合模式Composite(结构型) 1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 ...
- 设计模式(八)组合模式 Composite
组合模式: 允许你将对象组合成树形结构来表现“整体/部分”层次结构.组合能让客户以一致的方式处理个别对象以及对象组合. 组合模式适用于创建复杂的对象,这个对象包含某些个别的对象以及这些对象的组合. 从 ...
- Headfirst设计模式的C++实现——组合模式(Composite)
menu_component.h #ifndef _MENU_COMPONENT_H_ #define _MENU_COMPONENT_H_ #include <string> class ...
- Java设计模式(8)组合模式(Composite模式)
Composite定义:将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性. Composite比较容易理解,想到Composite就应该想到树 ...
- 乐在其中设计模式(C#) - 组合模式(Composite Pattern)
原文:乐在其中设计模式(C#) - 组合模式(Composite Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 组合模式(Composite Pattern) 作者:weba ...
- 设计模式系列之组合模式(Composite Pattern)——树形结构的处理
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- 浅谈设计模式--组合模式(Composite Pattern)
组合模式(Composite Pattern) 组合模式,有时候又叫部分-整体结构(part-whole hierarchy),使得用户对单个对象和对一组对象的使用具有一致性.简单来说,就是可以像使用 ...
- 二十四种设计模式:组合模式(Composite Pattern)
组合模式(Composite Pattern) 介绍将对象组合成树形结构以表示"部分-整体"的层次结构.它使得客户对单个对象和复合对象的使用具有一致性.示例有一个Message实体 ...
- 【设计模式】组合模式 Composite Pattern
树形结构是软件行业很常见的一种结构,几乎随处可见, 比如: HTML 页面中的DOM,产品的分类,通常一些应用或网站的菜单,Windows Form 中的控件继承关系,Android中的View继承 ...
- 设计模式 - 组合模式(composite pattern) 迭代器(iterator) 具体解释
组合模式(composite pattern) 迭代器(iterator) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考组合模式(composit ...
随机推荐
- CSS 命名规则
CSS书写顺序: 位置属性(position, top, right, z-index,display, float等) 大小(width, height, padding, margin) 文字系列 ...
- HBuilder开发app ajax跨域 解决XMLHttpRequest
<div id="a1" onclick="testXHR()" style="font-size: 5em;">sss1< ...
- hdu 2186
#include <iostream> using namespace std; int main() { int a,b,c,k1,k2,k3,m,n; cin>>m; wh ...
- 使用shiro标签遇到的部分问题的解决思路
最近几天,在shiro进行系统权限控制.在处理JSP页面的时候,遇到几个问题,纠结好几天,终于成功解决这些问题. 1.使用<shiro:principal>的时候,如何得到整个类的信息? ...
- 《Linux内核分析》 week4作业-使用嵌入式汇编调用一个系统调用
一.fork的嵌入式汇编执行 #include <stdio.h> #include <unistd.h> int main(){ pid_t pid; asm volatil ...
- JS判断字符串是否为空、过滤空格、查找字符串位置等函数集
这是一个由网上收集的JS代码段,用于判断指定字符串是否为空,过滤字符串中某字符两边的空格.查找指定字符串开始的位置.使用IsFloat函数判断一 个字符串是否由数字(int or long or fl ...
- await使用中的阻塞和并发
本文讨论,通过将Lambda还原成最普通的代码段,来解释上篇提出的疑问.并更正上篇中一些不太正确的写法.最后会给出无需等待Async方法返回值时,对Async方法使用await的建议,供大家参考.第一 ...
- weblogic使用脚本部署
--本机 (/common/bin/wlst.sh (2)connect('weblogic','weblogic1','t3://localhost:7001') (3)progress=deplo ...
- SQLiteDatabase中的事务
beginTransaction():开始事务endTransaction():结束事务SQLiteDatabase还提供了如下方法来判断当前上下文是否处于事物环境中.inTransaction(): ...
- Android AlertDialog全屏显示去除白色边框
使用styles.xml风格: Style.xml代码 <style name="FullScreenDialog" parent="android:style/T ...