1. 定义
组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。
可以在现实中找到模型。
比如公司的组织架构就是一棵树,总部下来会有财务、行政、人力、研发、市场等部门,每个部门下面又会有不同的子部门。
又比如文件结构。整体文件结构是一个树形结构,目录和文件,一个目录下面又会有子目录或者文件。
虽然一个是容器一个是叶子,但我们喜欢对这个树的所有节点都有一致的访问方式。
比如有同样的方式可以获取到大小、创建时间、修改时间,可以使用相同的接口进行增加、删除和修改。
树2. 设计
主要角色:
- 抽象构件,定义叶子和容器共有的方法。定义了访问子构件的方法,比如增加、修改、删除、获取。
- 叶子构件,实现抽象构件,因为没有子节点,可以使用异常处理访问子构件的方法。
- 容器构件,实现抽象构件,实现访问子构件的方法。
类图:
组合模式-类图使用者面向抽象构件编程,可以不用区分容器和叶子,统一处理。
抽象构件类,为了方便打印树,我们在执行方法加了一个深度信息,用来打印当前节点的深度。
public interface IComponent {
void sayHello(int deep);
void add(IComponent component);
void remove(IComponent component);
IComponent getChild(int i);
}
叶子节点,不允许有下级节点。所以子节点增删改查的方法要么不实现,要么直接抛出异常。
public class Leaf implements IComponent {
public void sayHello(int deep) {
for (int i = 0; i < deep; i++) {
System.out.print("-");
}
System.out.println("leaf hello");
}
public void add(IComponent component) {
}
public void remove(IComponent component) {
}
public IComponent getChild(int i) {
return null;
}
}
容器节点,维持对子节点列表的引用。
public class Composite implements IComponent {
private List<IComponent> components = new ArrayList<IComponent>();
public void sayHello(int deep) {
for (int i = 0; i < deep; i++) {
System.out.print("-");
}
System.out.println("composite hello.");
deep++;
for (IComponent component : components) {
component.sayHello(deep);
}
}
public void add(IComponent component) {
components.add(component);
}
public void remove(IComponent component) {
components.remove(component);
}
public IComponent getChild(int i) {
return components.get(i);
}
}
执行上面的例子。这里地方随意建立一棵树
public class TestComposite {
public static void main(String[] args) {
// 建立树
IComponent root = new Composite();
IComponent secondNode1 = new Composite();
root.add(secondNode1);
IComponent thirdNode = new Composite();
thirdNode.add(new Leaf());
thirdNode.add(new Leaf());
secondNode1.add(thirdNode);
secondNode1.add(new Leaf());
secondNode1.add(new Leaf());
IComponent secondNode2 = new Composite();
secondNode2.add(new Leaf());
root.add(secondNode2);
root.add(new Leaf());
root.add(new Leaf());
root.add(new Leaf());
// 执行
root.sayHello(0);
}
}
输出如下:
composite hello.
-composite hello.
--composite hello.
---leaf hello
---leaf hello
--leaf hello
--leaf hello
-composite hello.
--leaf hello
-leaf hello
-leaf hello
-leaf hello
统一的接口,让操作变得容易。
3. 应用
应用场景:
- 需要建立层次结构,区分整体和部分,提供有一致的接口。
- 需要建立对象树。
- 需要区分叶子和容器。
3.1. MyBatis:Plugin
3.2. Android:View 树
Android 系统中所有的 UI 都是基于 View 和 ViewGroup 创建的。
View 代表界面的一块矩形区域,可绘制,可响应交互事件。
ViewGroup 也是 View,同时还是 View 的容器。
然后 View 和 ViewGroup 的实现类,以树形结构组合在一起,创建复杂的手机页面。
Android 的 View 树是组合模式的典型应用。
Android View 树实际应用一般不会直接使用 View 和 ViewGroup,而是使用它们的子类。
比如 ViewGroup 的重要子类有:
- FrameLayout,帧布局。
- RelativeLayout,相对布局。
- LinnearLayout,线性布局。
- ConstraintLayout,约束布局。
- RecyclerView,列表。
等等,或者由应用者自定义容器。
View 的一些重要子类有:
- TextView,文本框。
- ImageView,图片控件。
- EditText,编辑框。
通过组合模式,把这一系列的 ViewGroup 和 View 组装成一棵树。很多重要的 UI 流程就是基于这棵树进行递归调用实现的。
- View 的计算,measure 过程。
- View 的布局,layout 过程。
- View 的绘制,draw 过程。
- 事件的传递分发。其中事件的处理过程采用的是责任链的方式。
4. 特点
4.1. 优势
- 屏蔽层次结构,客户端把精力放在节点对象的处理,忽略层次的差异。
- 简化代码,容器和叶子都视为抽象构件的具体实现,使用一致的接口访问。
- 易修改和扩展,新增容器和叶子无需对类库进行修改。
- 树的解决方案,组合模式可以通过递归操作进行建树。
4.2. 缺点
- 设计复杂,需要理解和理清层次关系。
网友评论