1. 概述
在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面。
例子1:就是多级树形菜单。
例子2:文件和文件夹目录
2.问题
我们可以使用简单的对象组合成复杂的对象,而这个复杂对象有可以组合成更大的对象。我们可以把简单这些对象定义成类,然后定义一些容器类来存储这些简单对象。客户端代码必须区别对象简单对象和容器对象,而实际上大多数情况下用户认为它们是一样的。对这些类区别使用,使得程序更加复杂。递归使用的时候跟麻烦,而我们如何使用递归组合,使得用户不必对这些类进行区别呢?
3. 解决方案
组合模式:将对象组合成树形状结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
组合模式让你可以优化处理递归或分级数据结构。有许多关于分级数据结构的例子,使得组合模式非常有用武之地。关于分级数据结构的一个普遍性的例子是你每次使用电脑时所遇到的:文件系统。文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,那么你可以使用组合模式Composite。
4. 组合模式的分类
1)将管理子元素的方法定义在Composite类中。
2)将管理子元素的方法定义在Component接口中,这样Leaf类就需要对这些方法
空实现。
5.涉及到的角色
1)Component是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为,声明一个接口用于访问和管理Component子部件。
2)Leaf 在组合中表示叶子结点对象,叶子结点没有子结点。
3)Composite定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。
6. 适用性
以下情况下适用Composite模式:
1)你想表示对象的部分-整体层次结构
2)你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象
7.结构
Composite结构图:
8.实例代码:
抽象组合类:
package com.component;
/**
* @author lxp
*
* @TODO
*
*/
//定义抽象组合类
public abstract class Component {
String name;
public Component(String name) {
this.name=name;
}
//添加组合对象的子对象
public abstract void Add(Component c);
//移除组合对象的子对象
public abstract void Remove(Component c);
//展现所有组合对象的子对象
public abstract void Display();
}
具体抽象类:
package com.component;
import java.util.ArrayList;
import java.util.List;
/**
* @author lxp
*
* @TODO
*
*/
//定义具体的组合类(根节点)
public class Composit extends Component {
//定义集合对象存储组合对象的子对象
List<Component> list=new ArrayList<Component>();
public Composit(String name) {
super(name);
// TODO Auto-generated constructor stub
}
//添加子对象(子节点)
@Override
public void Add(Component c) {
// TODO Auto-generated method stub
list.add(c);
}
//删除自对象(子节点)
@Override
public void Remove(Component c) {
// TODO Auto-generated method stub
list.remove(c);
}
//展示子对象(子节点)
@Override
public void Display() {
// TODO Auto-generated method stub
//输出添加的组合对象
System.out.println(name);
//遍历组合对象的子对象(树枝节点的叶子节点)
for(Component c:list){
c.Display();
}
}
}
组合对象的子对象类(叶子节点):
package com.component;
/**
* @author lxp
*
* @TODO
*
*/
//定义组合对象的子对象类(叶子节点)
public class Leaf extends Component{
public Leaf(String name) {
super(name);
// TODO Auto-generated constructor stub
}
//子对象(叶子节点)无需实现
@Override
public void Add(Component c) {
// TODO Auto-generated method stub
System.out.println("子类对象(叶子节点)没有添加功能");
}
//子类对象(叶子节点)无需实现
@Override
public void Remove(Component c) {
// TODO Auto-generated method stub
System.out.println("子类对象(叶子节点)没有移除功能");
}
//展现子类对象
@Override
public void Display() {
// TODO Auto-generated method stub
System.out.println(name);
}
}
测试类(客户端操作):
package com.component;
/**
* @author lxp
*
* @TODO
*
*/
//测试类
public class CompnentDemo {
public static void main(String[] args) {
//创建根节点
Composit rootComposit=new Composit("根节点");
//创建根节点的左树枝节点
Composit LeftComposit=new Composit("左树枝节点");
//创建根节点的右树枝节点
Composit RightComposit=new Composit("右树枝节点");
//向右树枝节点添加叶子节点
RightComposit.Add(new Leaf("右树枝节点—叶子节点A"));
RightComposit.Add(new Leaf("右树枝节点-叶子节点B"));
//将创建的树枝节点和叶子节点添加到根节点
rootComposit.Add(LeftComposit);
rootComposit.Add(RightComposit);
//展示根节点及其所有的子节点
rootComposit.Display();
}
}
试验结果: