组合模式

发布于: 2020 年 06 月 24 日
组合模式

什么是组合模式

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

组合模式的作用

  组合模式的目的是:让客户端不再区分操作的是组合对象还是叶子对象,而是以一个统一的方式来操作。实现这个目标的关键之处,是设计一个抽象的组件类,让它可以代表组合对象和叶子对象。这样一来,客户端就不用区分到底是组合对象还是叶子对象了,只需要全部当成组件对象进行统一的操作就可以了。

统一元素与部分整体,简化处理代码。

  1. 将元素内部结构同处理程序解耦,从而一致的对待元素与部分整体。

  2. 实际上,组合模式在应用中其实非常广泛,像文件系统、企业结构等都可以看做是组合模式的典型应用。

  3. Component:定义成接口或者抽象类,是元素与不部分整体的父类。

  4. Leaf:叶子节点,定义了基本元素的特征,继承自Component父类,是整体最基本的组成部分。

  5. Composite:部分整体或者容器,继承或实现自Component父类。内部包含Composite或者Leaf的聚合,用来保存内部的组织结构,并且针对该聚合有相应的操作方法。

组合模式的应用

  1. 在对象与部分整体之间,想要通过统一的方式对其进行处理,模糊处理其差异的时候可以选用组合模式。

  2. 当客户端忽视结构层次,无差异的看待元素与部分整体,不关心元素和部分整体之间的层次结构,想要实现对统一接口编程的时候。

  3. 对象的变化是动态,而客户端想要一致的处理对象的时候。

  4.组合模式意图是通过整体与局部之间的关系,通过树形结构的形式进行组织复杂对象,屏蔽对象内部的细节,对外展现统一的方式来操作对象,是我们处理更复杂对象的一个手段和方式。公司OA系统如何进行设计有关于此。   

  综上,在上述3种情况下可以考虑使用组合模式来设计系统程序。组合模式关键定义了一个抽象类或者接口,既可以代表元素又可以代表部分整体,而客户端是针对该接口进行编程。

组合模式的角色

Component(抽象构件)

它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。

Leaf(叶子构件)

它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。

Composite(容器构件)

它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。

组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。

组合模式的例子

用组合设计模式编写程序,打印输出图 1 的窗口,窗口组件的树结构如图 2 所示,打印输出示例参考图 3。

Component

可以使用接口或者抽象类

public interface PrinterComponent {
void print();
}

Composite

import static cn.hutool.core.collection.CollUtil.newArrayList;
import java.util.List;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class InputContainer implements PrinterComponent {
private String name;
private String action;
private List<PrinterComponent> components;
InputContainer add(PrinterComponent component) {
if (components == null) {
components = newArrayList();
}
this.components.add(component);
return this;
}
@Override
public void print() {
System.out.println(String.format("container: %s: %s", name, action));
components.forEach(PrinterComponent::print);
}
}

Leaf & main

import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class InputLeaf implements PrinterComponent {
private String name;
private String action;
@Override
public void print() {
System.out.println(String.format(" %s: %s", name, action));
}
public static void main(String[] args) {
InputContainer.builder()
.name("WinForm")
.action("WINDOW窗口")
.build()
.add(
InputContainer.builder()
.name("Frame")
.action("Logo Frame")
.build()
.add(InputLeaf.builder().name("Picture").action("LOGO图片").build())
)
.add(
InputContainer.builder()
.name("Frame")
.action("Message Frame")
.build()
.add(InputLeaf.builder().name("Lable").action("用户名").build())
.add(InputLeaf.builder().name("TextBox").action("文本框").build())
.add(InputLeaf.builder().name("Lable").action("密码").build())
.add(InputLeaf.builder().name("PasswordBox").action("密码框").build())
.add(InputLeaf.builder().name("CheckBox").action("复选框").build())
.add(InputLeaf.builder().name("TextBox").action("记住用户名").build())
.add(InputLeaf.builder().name("LinkLable").action("忘记密码").build())
)
.add(InputLeaf.builder().name("Button").action("登陆").build())
.add(InputLeaf.builder().name("Button").action("注册").build())
.print();
}
}

手写一个单例模

发布于: 2020 年 06 月 24 日 阅读数: 19
用户头像

俊俊哥

关注

还未添加个人签名 2013.06.01 加入

还未添加个人简介

评论

发布
暂无评论
组合模式