组合(Composite)模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
组合模式可以让客户端像修改配置文件一样简单的完成本来需要流程控制语句来完成的功能。
如下图所示:
文章图片
设计模式中的组合模式将对象组合成树形结果以表示“部分-整体”的层次结构,使得客户对单个对象和组合对象的使用具有一致性。上图为该模式的类图,其中Composite定义有子部件的那些部件的行为,组合部件的对象由Client通过Component提供的接口操作。
Component是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
Leaf在组合中表示叶子结点对象,叶子结点没有子结点。Composite定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。
具体来说,组合模式要在编程语言中实现,其实与《【C++】装饰器模式》(点击打开链接)差不多,最终实现之后,读取、操作某一个类,会一直追本溯源,找到最根本的类,然而其实现却是像《【C++】观察者模式》(点击打开链接)一样,把要操作的类不停地塞入数组,在最终要读取、操作的时候,对基类的数组进行遍历,同时其还可以任意对整体的各个部分操作。
下面用一道2010年下半年的软件设计师的软考说明这个问题,题目是这样的:某公司的组织结构图如图6-1所示,现采用组合(Composition)设计模式来设计,得到如图6-2所示的类图。
【【Java】组合模式】
文章图片
文章图片
其中Company为抽象类,定义了在组织结构图上添加(Add)和删除(Delete)分公司、办事处或者部分的方法接口,类ConcreteCompany表示具体的分公司或者办事处,分工是或者办事处下可以设置不同的部门。类HRDepartment和FinanceDepartment分别表示人力资源部和财务部。
具体代码如下:
import java.util.*;
//抽象公司类
abstract class Company {
private String name;
public Company(String name) {
super();
this.name = name;
} public Company() {
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} protected abstract void add(Company company);
protected abstract void remove(Company company);
protected abstract void display(int depth);
}//具体公司类,Concrete除了指 n.水泥 还有 adj.具体的(相对于 abstract adj.抽象的 而言)得意思
class ConcreteCompany extends Company {
private List cList;
//搞个数组用来存放下级公司 public ConcreteCompany() {
cList = new ArrayList();
} public ConcreteCompany(String name) {
super(name);
//这里其实同,this.name=name,其中name指代从抽象公司类的Company中继承下来的类成员name
cList = new ArrayList();
} @Override
protected void add(Company company) {
cList.add(company);
} @Override
protected void display(int depth) {//根据级别的不同,级别越低前面的横线越多
StringBuilder sb = new StringBuilder("");
for (int i = 0;
i < depth;
i++) {
sb.append("-");
}
System.out.println(new String(sb) + this.getName());
//打印横线与当前公司的名词
for (Company c : cList) {
c.display(depth + 2);
//每下一级,前面的横条就多2
}
} @Override
protected void remove(Company company) {
cList.remove(company);
}
}//这两个类,其实也是公司的子类,然而,其没有存放公司类的数组,故,注定是一个叶子节点,下面不得有子节点
//也就是断子绝孙的结点
class HRDepartment extends Company {
public HRDepartment(String name) {
super(name);
} @Override
protected void add(Company company) {
} @Override
protected void display(int depth) {
StringBuilder sb = new StringBuilder("");
for (int i = 0;
i < depth;
i++) {
sb.append("-");
}
System.out.println(new String(sb) + this.getName());
} @Override
protected void remove(Company company) {
}
}
//根本与HRDepartment是一模一样的,不解释。
class FinanceDepartment extends Company {
public FinanceDepartment(String name) {
super(name);
} @Override
protected void add(Company company) {
} @Override
protected void display(int depth) {
StringBuilder sb = new StringBuilder("");
for (int i = 0;
i < depth;
i++) {
sb.append("-");
}
System.out.println(new String(sb) + this.getName());
} @Override
protected void remove(Company company) {
}
}//具体实现
public class CompositionTest {
public static void main(String[] args) {
//先搞一个 北京总部
Company Beijing = new ConcreteCompany();
Beijing.setName("北京公司总部");
Beijing.add(new HRDepartment("总公司人力资源部"));
Beijing.add(new FinanceDepartment("总公司财务部"));
//再搞一个 上海分公司
Company Shanghai = new ConcreteCompany("上海分公司");
Shanghai.add(new FinanceDepartment("上海办事处财务部"));
Shanghai.add(new HRDepartment("上海办事处人力资源部"));
Beijing.add(Shanghai);
//将上海分公司置于北京总部之下//下逻辑同,不解释了
Company NanJing = new ConcreteCompany("南京办事处");
NanJing.add(new FinanceDepartment("南京办事处财务部"));
NanJing.add(new HRDepartment("南京办事处人力资源部"));
Shanghai.add(NanJing);
Beijing.display(0);
}
}
运行结果如下所示:
文章图片
符合题意,最后一句Beijing.display(0),是各个部门前面的横线从0开始,每下一级,多2条横线。
这里同时说一下,抽象类与接口的不同。
就是 抽象类里面除了定义抽象方法外,还可以定义类成员,其子类可以用super(某某类成员)拿下来用,彷如自己定义类成员一般。
而 接口里面只能定义 抽象方法。
就这么简单。
推荐阅读
- Java|Java基础——数组
- 人工智能|干货!人体姿态估计与运动预测
- java简介|Java是什么(Java能用来干什么?)
- Java|规范的打印日志
- Linux|109 个实用 shell 脚本
- 程序员|【高级Java架构师系统学习】毕业一年萌新的Java大厂面经,最新整理
- Spring注解驱动第十讲--@Autowired使用
- SqlServer|sql server的UPDLOCK、HOLDLOCK试验
- jvm|【JVM】JVM08(java内存模型解析[JMM])
- 技术|为参加2021年蓝桥杯Java软件开发大学B组细心整理常见基础知识、搜索和常用算法解析例题(持续更新...)