设计模式 | 组合模式的初步学习

注意:本文内容是对 该博客 的学习。

组合模式

组合模式的概念

组合模式的定义

组合(composite)模式,有时又叫做部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象有一致的访问性。
在这里插入图片描述

组合模式的结构

抽象构件(componet)角色: 它的主要作用是为树叶构件和树枝构件声明公共接口,并实现他们的缺省行为(就是默认的行为,通常指共同拥有的方法等)。

透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构建完成。

树叶构件(leaf)角色: 是组合中的叶节点对象,它没有子节点,用于实现抽象构件角色中声明的公共接口。

树枝构件(composite)角色: 是组合中的分支节点对象,它有子节点。它实现了抽象构建角色中声明的接口。它的主要作用是存储和管理子部件,通常包含add(),remove(),getChild()等方法。

我对组合模式的理解是:组合模式利用了树的特性。因为树可以递归到每一个子节点,因而当我们对树的根进行操作的时候,就可以递归的对每一个节点进行操作,这样,我们可以把树的根看做这颗树的代表,即整体,把其他的实体类(leaf和composite)作为树的节点,当我们操作这棵树的根的时候,就相当于操作每一个节点了(递归的访问每一个节点)。

比如我们要树和客户A通话,只需要调用树的根与与A通话的方法,这个方法递归的遍历每一个节点,最终的效果是所有的节点都与A通话了。

透明式的组合模式

在该方式中,由于抽象构件中声明了所有子类中的全部方法,所以客户端无需区别树叶对象和树枝对象,对于客户端来说是透明的,下面是其结构图:
在这里插入图片描述

安全式的组合模式

在该方法中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性,下面是其结构图:
在这里插入图片描述
我对这两个模式的理解:二者的区别是透明模式里对子对象操作的方法在抽象类里就有,而安全式里对子对象操作的方法只有树枝构件有。顾名思义,因为在透明式的组合模式中,用户直接操作根节点就完事了,所以这个模式对于客户是透明的,但这样不安全,因为抽象类中的操作子节点的方法在树叶节点中根本没有实现,如果客户对树叶节点调用操作子节点方法,就会抛出异常。

换言之,把操作子节点的方法放在树枝构件里,不放在抽象构件,就可以解决这个安全问题,因而它叫做安全式的组合模式。而安全式的缺点就是,用户在调用的时候,得分清楚自己调用的是树叶对象还是树枝对象,这就不够透明了。

组合模式的例子

该博客 中用了一个非常好理解的例子来帮助我们理解组合模式,那就是文件夹的管理。

我们来实现一个简单的目录树,有文件夹和文件两种类型,首先需要一个抽象构件类,声明了文件夹类和文件类需要的方法。

//文件夹-文件 就是组合模式的一种典型用法
public abstract class Component {
	public String getName() {
		throw new UnsupportedOperationException("不支持获取名称操作!");
	};
	public void add(Component component){
		throw new UnsupportedOperationException("不支持添加操作!");
	};
	public void remove(Component component){
		throw new UnsupportedOperationException("不支持删除操作!");
	};
	public String getContent(){
		throw new UnsupportedOperationException("不支持获取内容操作!");
	};
	public void print(){
		throw new UnsupportedOperationException("不支持打印操作!");
	};
	
}

实现一个文件夹类 Folder,继承 Component,定义一个 List 类型的componentList属性,用来存储该文件夹下的文件和子文件夹,并实现 getName、add、remove、print等方法

//文件夹就是树枝节点(composite)
public class Folder extends Component {

	private String name;
	private List<Component> componentList = new ArrayList<Component>();
	private Integer level;
	public Folder(String name) {
		this.name = name;
	}
	@Override
	public String getName() {
		
		// TODO Auto-generated method stub
		return this.name;
	}

	@Override
	public void add(Component component) {
		// TODO Auto-generated method stub
		this.componentList.add(component);
	}

	@Override
	public void remove(Component component) {
		// TODO Auto-generated method stub
		this.componentList.remove(component);
	}

	@Override
	public void print() {
		System.out.println(this.getName());
		if(this.level == null) {
			this.level = 1;
		}
		String prefix = "";
		for(int i = 0; i < this.level; ++i) {
			prefix += "\t- ";
		}
		for (Component component : this.componentList) {
			if(component instanceof Folder) {
				((Folder) component).level = this.level + 1; 
			}
			System.out.print(prefix);
			component.print();
		}
		this.level = null;
		// TODO Auto-generated method stub
	}

}

文件类 File,继承Component父类,实现 getName、print、getContent等方法

public class File extends Component {
	private String name;
	private String content;
	public File(String name, String content) {
		this.name = name;
		this.content = content;
	}
	public String getName() {
		return this.name;
	}
	public String getContent() {
		return this.content;
	}
	public void print() {
		System.out.println(this.getName());
	}
}

组合模式的优缺点

优点:

  • 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无需关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
  • 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而改变源代码,满足“开闭原则”。

缺点:

  • 设计较为复杂,客户端需要花更多的时间理清类之间的层次关系;
  • 不容易限制容器中的构件
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值