《Head-First-设计模式》笔记13-组合模式
定义
组合模式允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能够让客户以一致的方式处理个别对象以及对象组合。
使用组合结构,我们能把相同的操作应用在组合和个别对象上。换句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。
类图
- Component:为组合中的对象声明接口。
- Leaf:在组合中表示没有子节点的叶节点。
- Composite:定义有枝节点行为,用来存储子部件,在 Component 接口中实现与子部件有关操作,如增加(add)和删除(remove)等。
实例
文件系统,文件系统里有文件和文件夹,文件夹里又有文件夹和文件...
定义 Directory 基类
所有组件必须实现 Directory 接口,然而叶节点和组合节点的角色不同,所有有些方法并不适用。面对这种情况,有时候最好是抛出运行时异常。
public abstract class Directory {
String name;
String description;
/**
* 添加指定文件/文件夹到该目录下
* @param dir 将要添加的文件/文件夹
* @return 添加成功/失败
*/
public boolean add(Directory dir){
throw new UnsupportedOperationException();//默认抛出操作异常
}
/**
* 删除该目录下的指定文件/文件夹
* @param dir 将要删除的文件/文件夹
* @return 删除成功/失败
*/
public boolean remove(Directory dir){
throw new UnsupportedOperationException();//默认抛出操作异常
}
/**
* 清空该目录下所有文件和文件夹
* @return 清空成功/失败
*/
public boolean clear(){
throw new UnsupportedOperationException();//默认抛出操作异常
}
public abstract void print();
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String toString(){
return name + description;
}
}
MyFile 类
由于基类中对 MyFile 不支持的操作都做了默认实现(抛出异常),所以 MyFile 变得相当苗条。
public class MyFile extends Directory{
public MyFile(String name, String desc) {
this.name = name;
this.description = desc;
}
@Override
public void print() {
System.out.print(this.toString());//输出文件自身信息
}
}
Folder 类
public class Folder extends Directory{
ArrayList<Directory> files;
public Folder(String name, String desc){
this.name = name;
this.description = desc;
this.files = new ArrayList<Directory>();
}
@Override
public void print() {
//打印该Folder自身信息
System.out.print(this.toString() + "(");
//打印该目录下所有文件及子文件
// for(Directory dir : files){
// dir.print();
// System.out.print(", ");
// }
Iterator<Directory> iter = getFiles().iterator();
while(iter.hasNext()){
Directory dir = iter.next();
dir.print();
if(iter.hasNext()){
System.out.print(",");
}
}
System.out.print(")");
}
@Override
public boolean add(Directory dir){
if(files.add(dir))
return true;
else
return false;
}
@Override
public boolean remove(Directory dir){
if(files.remove(dir))
return true;
else
return false;
}
@Override
public boolean clear(){
files.clear();
return true;
}
public ArrayList<Directory> getFiles() {
return files;
}
}
测试
public class Test {
public static void main(String[] args){
/*构造文件树*/
/*
C
a.txt
b.txt
system
sys.dat
windows
win32
settings
log.txt
win32.config
*/
Directory dir = new Folder("C", "");
dir.add(new MyFile("a.txt", ""));
dir.add(new MyFile("b.txt", ""));
Directory subDir = new Folder("system", "");
subDir.add(new MyFile("sys.dat", ""));
dir.add(subDir);
Directory subDir2 = new Folder("windows", "");
Directory subDir3 = new Folder("win32", "");
subDir3.add(new Folder("settings", ""));
subDir3.add(new MyFile("log.txt", ""));
subDir2.add(subDir3);
subDir2.add(new MyFile("win32.config", ""));
dir.add(subDir2);
dir.print();//打印输出文件树
}
}/* output:
C(a.txt, b.txt, system(sys.dat, ), windows(win32(settings(), log.txt, ), win32.config, ), )
*/
关于是否抛出异常
有些时候我们可以选择返回 null,返回 false,返回错误码等等而不是抛出异常,这些方式或许更和谐一些,但抛出异常在有些时候是对事实最贴切的表达。
举个例子,假设我们的 Folder 类有一个 add 方法,表示是否存在与之关联的应用程序,而 MyFile 不支持 add 方法,同时该属性又是从父类继承得到的,我们无法删除它。
此时我们可以选择返回 false 或者抛出异常:
返回 false:表示 MyFile 没有与之关联的应用程序
抛出异常:表示 MyFile 不支持该操作
显然,抛出异常的含义才是我们真正想要表达的
总结
- 组合模式提供一个结构,可同时包容个别对象和组合对象。
- 组合模式允许客户对个别对象以及组合对象一视同仁。
- 组合结构内的任意对象称为组件,组件可以是组合,也可以是叶节点。
- 在实现组合模式时,有许多设计上的折中。你要根据需要平衡透明性和安全性。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com
文章标题:《Head-First-设计模式》笔记13-组合模式
文章字数:1.1k
本文作者:Bin
发布时间:2018-07-15, 10:17:34
最后更新:2019-08-06, 00:07:35
原始链接:http://coolview.github.io/2018/07/15/Head-First-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E3%80%8AHead-First-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%8B%E7%AC%94%E8%AE%B013-%E7%BB%84%E5%90%88%E6%A8%A1%E5%BC%8F/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。