八、组合模式(Composite Pattern)

1. 意图

将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象
和组合对象的使用具有一致性

2. 动机

栗子的公司需要做一个文件的浏览系统,要求可以浏览文件夹和各种文件,栗子很快拿出了v1.0版的方案:做了一个文件夹类,两个具体的文件类(txt,img)
八、组合模式(Composite Pattern)_第1张图片
很快他发现,如果需要增加一个zip类型,他需要新增一个ZipFile,并且需要修改原来的Folder类,违反了开闭原则(Open Closed Principle,OCP)

3. 适用性

  • 适用于解决整体-部分结构类型的问题
  • 客户端希望忽略整体与部分的差异,从而统一的使用它们

4. 结构(透明式的组合模式)

八、组合模式(Composite Pattern)_第2张图片

5. 参与者

  • 容器:是一个抽象类,统一的表示整体和部分
  • 组合:既可以当作节点,也可以当作容器
  • 叶子:节点对象

6. 代码示例

  • 容器
package com.lt.component;

/**
 * @author lt
 * @date 2019年4月17日
 * @version v1.0
 */
public abstract class Component {

	public abstract boolean add(Component e);
	public abstract boolean remove(Component e);
	public abstract Component getChild(int index);
	public abstract void getMsg();
}
  • 组合
package com.lt.composite;

import java.util.ArrayList;
import java.util.List;

import com.lt.component.Component;

/**
 * @author lt
 * @date 2019年4月17日
 * @version v1.0
 */
public class Folder extends Component {

	private List list = new ArrayList<>();
	
	private String name;
	public Folder(String name){
		this.name = name;
	}
	@Override
	public boolean add(Component e) {
		return list.add(e);
	}

	@Override
	public boolean remove(Component e) {
		return list.remove(e);
	}

	@Override
	public Component getChild(int index) {
		return list.get(index);
	}

	@Override
	public void getMsg() {
		System.out.println("文件夹:"+name);
		for(Component e : list){
			e.getMsg();
		}
	}

}
  • 叶子
package com.lt.life;


import com.lt.component.Component;

/**
 * @author lt
 * @date 2019年4月17日
 * @version v1.0
 */
public class ImgFile extends Component {

	private String name;
	public ImgFile(String name){
		this.name = name;
	}
	@Override
	public boolean add(Component e) {
		throw new RuntimeException("leaf无法添加子元素");
	}

	@Override
	public boolean remove(Component e) {
		throw new RuntimeException("leaf无法删除");
	}

	@Override
	public Component getChild(int index) {
		throw new RuntimeException("leaf没有子元素");
	}

	@Override
	public void getMsg() {
		System.out.println("图像文件:"+name);
	}

}
package com.lt.life;


import com.lt.component.Component;

/**
 * @author lt
 * @date 2019年4月17日
 * @version v1.0
 */
public class TxtFile extends Component {


	private String name;
	public TxtFile(String name){
		this.name = name;
	}
	@Override
	public boolean add(Component e) {
		throw new RuntimeException("leaf无法添加子元素");
	}

	@Override
	public boolean remove(Component e) {
		throw new RuntimeException("leaf无法删除");
	}

	@Override
	public Component getChild(int index) {
		throw new RuntimeException("leaf没有子元素");
	}

	@Override
	public void getMsg() {
		System.out.println("文本文档:"+name);
	}

}

7. 已知应用

Java SE中的AWT,和Swing大量使用了组合模式,Component类是抽象构件,Checkbox、Button和TextComponent是叶子构件,而Container是容器构件

8. 相关模式

  • 通常部件-父部件连接用于责任链模式模式。
  • 装饰者模式经常与组合模式一起使用。当装饰和组合一起使用时,它们通常有一个公共的父类。因此装饰必须支持具有Add、Remove和GetChild操作的Component
  • 享元模式让你共享组件,但不再能引用他们的父部件。
  • Itertor(5.4)可用来遍历Composite。
  • Visitor(5.11)将本来应该分布在Composite和Leaf类中的操作和行为局部化。

9. 疑问

参考

【1】《Design Patterns: Elements of Reusable Object-Oriented Software》
【2】Java设计模式:23种设计模式全面解析
【3】java设计模式之组合模式

你可能感兴趣的:(设计模式,04.设计模式)