【笔记整理】图解设计模式 | 第11章 Composite模式(容器与内容的一致性)

【笔记整理】图解设计模式 | 导航


定义

  • 能够使容器与内容具有一致性,创造出递归结构的模式就是Composite模式。

Composite模式中的登场角色

  • Leaf(树叶)

       表示“内容”的角色。在该角色中不能放入其他对象。

  • Composite(复合物)

       表示容器的角色。可以在其中放入Leaf角色和Composite角色。

  • Component(一致性)

       使Leaf角色和Composite角色具有一致性的角色。Composite角色是Leaf角色和Composite角色的父类。

  • Client

       使用Composite模式的角色。


Composite模式的类图

在该图中,可以将Composite角色与它内部的Component角色(即Leaf角色或Composite角色)看成是父亲和孩子们的关系。getChild方法的作用是从Component角色获取这些“孩子们”


拓展思路的要点

  • 多个和单个的一致性

       使用Composite模式可以使容器与内容具有一致性,也可以称其为多个和单个的一致性,即将多个对象结合在一起,当作一个对象进行处理。

  • Add方法应该放在那里

       方法1:定义在Entry类中,报错(最佳方案)

       方法2:定义在Entry类中,但什么都不做

       方法3:声明在Entry类中,但不实现

       方法4:只定义在Directory类中

  • 到处都存在递归结构

       在程序世界中,到处都存在递归结构和Composite模式。例如在视窗系统中,一个窗口可以含有一个子窗口,这就是Composite模式的典型应用。此外,在文章的列表中,各列表之间可以相互嵌套,这也是一种递归结构。将多条计算机命令合并为一条宏命令时,如果使用递归结构实现宏命令,那么还可以编写出宏命令的宏命令。另外,通常来说,树结构的数据结构都适用Composite模式。


相关的设计模式

  • Command模式(第22章)

       使用Command模式编写宏命令时使用了Composite模式。

  • Visitor模式(第13章)

       可以使用Visitor模式访问Composite模式中的递归结构。

  • Decorator模式(第12章)

       Composite模式通过Component角色使容器(Composite角色)和内容(Leaf角色)具有一致性,Component角色中有操作child的方法add、remove以及getChild,Composite角色里面有一个名为children的集合

       Decorator模式使装饰框和内容具有一致性,装饰器角色中有一个被装饰物的实例


       代码

  • Component(一致性)
public abstract class Entry {

	protected Entry parent; // 父节点

	public abstract String getName(); // 获取名字

	public abstract int getSize(); // 获取大小

	public Entry add(Entry entry) throws FileTreatMentException { // 加入目录条目
		throw new FileTreatMentException();
	}

	public void printList() { // 显示目录条目一览
		printList("");
	}

	protected abstract void printList(String prefix); // 为一览加上前缀并显示目录条目一览

	@Override
	public String toString() { // Template模式
		return getName() + " (" + getSize() + ")";
	}

	public String getFullName() {
		StringBuffer fullname = new StringBuffer();
		Entry entry = this;
		do {
			fullname.insert(0, "/" + entry.getName());
			entry = entry.parent;
		} while (entry != null);
		return fullname.toString();
	}
}
  • Leaf(树叶)
public class File extends Entry {

	private String name;

	private int size;

	public File(String name, int size) {
		this.name = name;
		this.size = size;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public int getSize() {
		return size;
	}

	@Override
	protected void printList(String prefix) {
		System.out.println(prefix + "/" + this);
	}

}
  • Composite(复合物)
public class Directory extends Entry {

	private String name; // 文件夹的名字
	private List<Entry> directory = new ArrayList<Entry>(); // 文件夹中目录条目的集合

	public Directory(String name) { // 构造函数
		this.name = name;
	}

	@Override
	public String getName() { // 获取名字
		return name;
	}

	@Override
	public int getSize() {
		int size = 0;
		Iterator<Entry> it = directory.iterator();
		while (it.hasNext()) {
			size += it.next().getSize(); // 递归
		}
		return size;
	}

	public Entry add(Entry entry) { // 增加目录条目
		directory.add(entry);
		entry.parent = this; // 加入文件夹时,记录父节点
		return this;
	}

	@Override
	protected void printList(String prefix) {
		System.out.println(prefix + "/" + this);
		Iterator<Entry> it = directory.iterator();
		while (it.hasNext()) {
			it.next().printList(prefix + "/" + name); // 递归
		}
	}

}
  • 异常类
public class FileTreatMentException extends RuntimeException {

	private static final long serialVersionUID = 1L;

	public FileTreatMentException() {
	}

	public FileTreatMentException(String message) {
		super(message);
	}
}
  • Client
public class Main {

	public static void main(String[] args) {
		System.out.println("Making root entries...");
		Directory rootdir = new Directory("root");
		Directory bindir = new Directory("bin");
		Directory tmpdir = new Directory("tmp");
		Directory usrdir = new Directory("usr");

		rootdir.add(bindir);
		rootdir.add(tmpdir);
		rootdir.add(usrdir);

		bindir.add(new File("vi", 10000));
		bindir.add(new File("latex", 20000));

		rootdir.printList();

		System.out.println("");
		System.out.println("Making user entries...");
		Directory yuki = new Directory("yuki");
		Directory hanako = new Directory("hanako");
		Directory tomura = new Directory("tomura");
		usrdir.add(yuki);
		usrdir.add(hanako);
		usrdir.add(tomura);
		yuki.add(new File("diary.html", 100));
		File file = new File("Composite.java", 200);
		yuki.add(file);
		hanako.add(new File("memo.tex", 300));
		hanako.add(new File("game.doc", 400));
		hanako.add(new File("junk.mail", 500));
		rootdir.printList();

		System.out.println("");
		System.out.println("file = " + file.getFullName());

	}
}

注:博客中的图片来自网上。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值