组合模式
2019年5月23日21:50:31
组合模式(composite pattern)
定义
组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。————《设计模式:可复用面向对象软件的基础》
组合模式是一个结构型模式。
使用场景
当你发现需求中是用树形结构体现部分与整体层次关系的结构时,且你希望用户可以忽略整体和部分、组合对象和单个对象的不同,统一地使用组合结构中的所有对象时,就应该使用组合模式。
组合模式解决上面所说的两个问题:
1、部分与整体的层次关系表示为树形结构、
2、部分与整体的对象,是能让客户端能统一对待、不需区分的对象。
场景:树形菜单,文件、文件夹的管理。
角色
抽象组件角色(Component):
- 所有组件的抽象
- 声明在组合模式中的对象的接口
叶子角色(Leaf):
- 表示组合模式中的叶子对象
- 实现了Component
- 没有子节点
组合角色(Composite):
- 表示一个组合组件(拥有叶子节点)
- 实现了Component,
- 拥有子节点,并具备操作Component的方法,增加组件、删除组件等
图示
组合模式结构图:
代码示例
深圳某公司总部使用的OA系统,由于简单易用,反响良好的原因,准备被推广到各分公司使用。
关于组织结构的设计,原来是这样的:一个公司总部下面有人力资源部、财务部等。组织结构图如下:
类图如下:
代码如下:
// 组织
public interface Organization {
void addOrg(Department department);
void removeOrg(Department department);
String getName();
void showOrg();
void displayDuty();
}
// 公司总部
public class Headquarters implements Organization {
private List<Department> departments = new ArrayList<>();
@Override
public void addOrg(Department department) {
departments.add(department);
}
@Override
public void removeOrg(Department department) {
departments.remove(department);
}
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public void showOrg() {
System.out.println("-" + getName());
for (Department department : departments) {
System.out.println("--" + department.getName());
}
}
@Override
public void displayDuty() {
for(Department department : departments) {
department.duty();
}
}
}
// 部门
public interface Department {
String getName();
void duty();
}
// 财务部
public class FinanceDepartment implements Department {
@Override
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public void duty() {
System.out.println("财务部负责公司财务收支管理");
}
}
// 人力资源部
public class HumanResourceDepartment implements Department{
@Override
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public void duty() {
System.out.println("人力资源部负责员工招聘培训管理");
}
}
// 测试类
public class Before {
public static void main(String[] args) {
Organization hq = new Headquarters();
Department fnc = new FinanceDepartment();
Department hr = new HumanResourceDepartment();
hq.addOrg(fnc);
hq.addOrg(hr);
System.out.println("====组织结构====");
hq.showOrg();
System.out.println("====部门职责====");
hq.displayDuty();
}
}
测试结果:
组织结构需求现在变成了:总部下面不仅是只有部门,还会有分公司。之前的设计明显是不可以用了,接口Organization中addOrg、removeOrg方法都是面对于Department的。现在需要不区分部门、分公司和总部,且组织结构是用树形结构来体现层次关系的。组合模式就派上用场了。
推广之后组织机构图:
应用组合模式的类图:
应用组合模式的代码:
// 公司组织或部门
public interface Company {
void addOrg(Company company);
void removeOrg(Company company);
void showOrg(int depth);
default void print(int dept) {
while(dept-- > 0) {
System.out.print("-");
}
}
}
// 总部或分公司
public class ConcreteComp implements Company {
private String name = "";
private List<Company> companies = new ArrayList<>();
ConcreteComp(String name) {
this.name = name;
}
@Override
public void addOrg(Company company) {
companies.add(company);
}
@Override
public void removeOrg(Company company) {
companies.remove(company);
}
@Override
public void showOrg(int dept) {
print(dept);
System.out.println(this.name);
for (Company c : companies) {
c.showOrg(dept + 2);
}
}
}
// 财务部
public class FinanceDepartment implements Company {
private String name = "";
FinanceDepartment(String name) {
this.name = name;
}
@Override
public void addOrg(Company company) {
}
@Override
public void removeOrg(Company company) {
}
@Override
public void showOrg(int dept) {
print(dept);
System.out.println(this.name);
}
}
// 人力资源部
public class HumanResourceDepartment implements Company {
private String name = "";
HumanResourceDepartment(String name) {
this.name = name;
}
@Override
public void addOrg(Company company) {
}
@Override
public void removeOrg(Company company) {
}
@Override
public void showOrg(int dept) {
print(dept);
System.out.println(this.name);
}
}
// 测试类
public class After {
public static void main(String[] args) {
Company headquarters = new ConcreteComp("公司总部");
headquarters.addOrg(new FinanceDepartment("财务部"));
headquarters.addOrg(new HumanResourceDepartment("人力资源部"));
Company gd = new ConcreteComp("广东分公司");
gd.addOrg(new FinanceDepartment("财务部"));
gd.addOrg(new HumanResourceDepartment("人力资源部"));
Company sz = new ConcreteComp("深圳分公司");
sz.addOrg(new FinanceDepartment("财务部"));
sz.addOrg(new HumanResourceDepartment("人力资源部"));
gd.addOrg(sz);
Company sh = new ConcreteComp("上海分公司");
sh.addOrg(new FinanceDepartment("财务部"));
sh.addOrg(new HumanResourceDepartment("人力资源部"));
headquarters.addOrg(gd);
headquarters.addOrg(sh);
headquarters.showOrg(1);
Company test = new FinanceDepartment("测试财务部");
test.addOrg(new HumanResourceDepartment("测试人力资源部"));
test.addOrg(sh);
test.showOrg(1);
}
}
测试结果:
总部下可以添加分公司和部门,分公司下也可以添加分公司和部门,甚至部门下也可以添加分公司和部门,做到了不用区分整体和部分。只是部门下添加分公司和部门是不起作用的。
透明方式与安全方式
上面应用组合模式的方式就是透明方式,接口Company定义了addOrg、removeOrg方法,无论是叶子角色还是树枝角色都拥有addOrg、removeOrg方法,从实际使用的角度来说,叶子角色不需要这两个方法。对于外界来说,叶子和树枝的区别是透明的,这就是透明方式。
安全方式就是接口Company里没有定义addOrg、removeOrg方法,只在树枝角色添加addOrg、removeOrg方法。这样用户需要对叶子角色和树枝角色进行判断能不能使用ddOrg、removeOrg方法。
透明方式的缺点是叶子角色在添加叶子或者树枝时是什么也不做,用户觉得应该是操作成功了,但是并没有操作成功。安全方式的缺点就是在添加叶子和树枝的时候需要进行判断。
优点
对服务端来说,以树形结构清晰定义了整体和部分的层次关系,只需要知道自己的父节点就可以自由添加子节点。
对客户端来说,可以忽略整体和部分的差异,不需关心是单个对象还是组合对象,简化了逻辑。
总结
组合模式是将对象 组合成树形结构以表示‘部分-整体’的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
参考
《大话设计模式》
完
2019年7月18日20:09:21
由于博主水平有限,如果本文有什么错漏,请不吝赐教
感谢阅读,如果您觉得本文对你有帮助的话,可以点个推荐
posted on 2019-07-19 20:08 mingmingcome 阅读(798) 评论(0) 编辑 收藏 举报