1.什么是组合模式
对于树形结构,当容器对象(如文件夹)的某一个方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员对象(可以是容器对象,也可以是叶子对象)并调用执行,牵一而动百,其中使用了递归调用的机制来对整个结构进行处理。由于容器对象和叶子对象在功能上的区别,在使用这些对象的代码中必须有区别地对待容器对象和叶子对象,而实际上大多数情况下我们希望一致地处理它们,因为对于这些对象的区别对待将会使得程序非常复杂。组合模式为解决此类问题而诞生,它可以让叶子对象和容器对象的使用具有一致性。
其实就是一个树状结构的实现看图就知道了:
2.组合模式的实现方式
例子: 在Sunny软件公司的内部办公系统Sunny OA系统中,有一个与公司组织结构对应的树形菜单,行政人员可以给各级单位下发通知,这些单位可以是总公司的一个部门,也可以是一个分公司,还可以是分公司的一个部门。用户只需要选择一个根节点即可实现通知的下发操作,而无须关心具体的实现细节。
分析: 也就是说:公司是基础容器,部门是叶子节点
实现方式: 1.透明模式
2.安全模式
分析: 也就是说:公司是基础容器,部门是叶子节点
实现方式: 1.透明模式
2.安全模式
1).透明模式
TransparentMode.java
package cn.limbo.design_patterns.composite.transparent_mode;
/**
* 透明组合模式下的基础容器定义
* 定义为抽象类的原因是为了提供一些缺省的方法实现
* Created by limbo on 2016/12/2.
*/
public abstract class TransparentMode {
//添加
public void add(TransparentMode transparentMode) {
System.out.println("对不起,不支持该方法...");
}
//移除
public void remove(TransparentMode transparentMode) {
System.out.println("对不起,不支持该方法...");
}
public TransparentMode getChild(int i) {
System.out.println("对不起,不支持该方法...");
return null;
}
public abstract void infrom();
}
TransparentCompany.java
package cn.limbo.design_patterns.composite.transparent_mode;
import java.util.ArrayList;
/**
* 透明模式的公司类,用作基础容器进行使用
* Created by limbo on 2016/12/2.
*/
public class TransparentCompany extends TransparentMode {
private String companyName;
//用于存储TransparentMode对象
private ArrayList<TransparentMode> departments = new ArrayList<>();
public TransparentCompany(String companyName) {
this.companyName = companyName;
}
//修改缺省方法实现
@Override
public void add(TransparentMode transparentMode) {
this.departments.add(transparentMode);
}
@Override
public void remove(TransparentMode transparentMode) {
this.departments.remove(transparentMode);
}
@Override
public TransparentMode getChild(int i) {
return this.departments.get(i);
}
//自定义通知行为,这里只是普通业务类的一个代表
@Override
public void infrom() {
System.out.println(this.companyName + "正在往下属部门分发通知...");
for (TransparentMode tmp : this.departments) {
tmp.infrom();
}
}
}
TransparentDepartment.java
package cn.limbo.design_patterns.composite.transparent_mode;
/**
* 透明模式的部门类,也就是组合设计模式中的叶子节点
* Created by limbo on 2016/12/2.
*/
public class TransparentDepartment extends TransparentMode {
private String departmentName;
public TransparentDepartment(String departmentName) {
this.departmentName = departmentName;
}
//发送通知
@Override
public void infrom() {
System.out.println(this.departmentName + "正在给员工发送通知...");
}
}
2).安全模式
SecurityMode.java
package cn.limbo.design_patterns.composite.security_mode;
/**
* 安全组合模式的基础容器的实现模式
* 个人认为使用接口实现更加好一点,因为不需要提供默认的方法实现,只要实现了容器标准就可以
* Created by limbo on 2016/12/2.
*/
public interface SecurityMode {
public void inform();
}
SecurityCompany.java
package cn.limbo.design_patterns.composite.security_mode;
import java.util.ArrayList;
/**
* 安全模式公司类
* Created by limbo on 2016/12/2.
*/
public class SecurityCompany implements SecurityMode {
private String companyName;
//公司下属的分公司或者是部门
private ArrayList<SecurityMode> departments = new ArrayList<>();
public SecurityCompany(String companyName) {
this.companyName = companyName;
}
//添加
public void add(SecurityMode securityMode) {
this.departments.add(securityMode);
}
//移除
public void remove(SecurityMode securityMode) {
this.departments.remove(securityMode);
}
//获取子元素
public SecurityMode getChild(int i) {
return this.departments.get(i);
}
//自定义通知行为,这里只是普通业务类的一个代表
@Override
public void inform() {
System.out.println(this.companyName + "正在往下属部门分发通知...");
for (SecurityMode tmp : this.departments) {
tmp.inform();
}
}
}
SecurityDepartment.java
package cn.limbo.design_patterns.composite.security_mode;
/**
* Created by limbo on 2016/12/2.
*/
public class SecurityDepartment implements SecurityMode {
private String departmentName;
public SecurityDepartment(String departmentName) {
this.departmentName = departmentName;
}
@Override
public void inform() {
System.out.println(this.departmentName + "正在给员工发送通知...");
}
}
测试类:
package cn.limbo.test;
import cn.limbo.design_patterns.composite.security_mode.SecurityCompany;
import cn.limbo.design_patterns.composite.security_mode.SecurityDepartment;
import cn.limbo.design_patterns.composite.transparent_mode.TransparentCompany;
import cn.limbo.design_patterns.composite.transparent_mode.TransparentDepartment;
import cn.limbo.design_patterns.composite.transparent_mode.TransparentMode;
import org.junit.Test;
/**
* 组合模式测试类
* Created by limbo on 2016/12/2.
*/
public class CompositeTest {
@Test
public void show(){
// transparentModeTest();
securityModeTest();
}
private static void transparentModeTest(){
TransparentMode mainCompany = new TransparentCompany("总公司");
TransparentMode subCompany_0 = new TransparentCompany("子公司-0");
TransparentMode subCompany_1 = new TransparentCompany("子公司-1");
TransparentMode department_0 = new TransparentDepartment("A部门");
TransparentMode department_1 = new TransparentDepartment("B部门");
TransparentMode department_2 = new TransparentDepartment("C部门");
TransparentMode department_3 = new TransparentDepartment("D部门");
TransparentMode department_4 = new TransparentDepartment("E部门");
mainCompany.add(subCompany_0);
mainCompany.add(subCompany_1);
subCompany_0.add(department_0);
subCompany_0.add(department_1);
subCompany_1.add(department_2);
subCompany_1.add(department_3);
subCompany_1.add(department_4);
mainCompany.infrom();
}
private static void securityModeTest(){
SecurityCompany mainCompany = new SecurityCompany("总公司");
SecurityCompany subCompany_0 = new SecurityCompany("子公司-0");
SecurityCompany subCompany_1 = new SecurityCompany("子公司-1");
SecurityDepartment department_0 = new SecurityDepartment("A部门");
SecurityDepartment department_1 = new SecurityDepartment("B部门");
SecurityDepartment department_2 = new SecurityDepartment("C部门");
SecurityDepartment department_3 = new SecurityDepartment("D部门");
SecurityDepartment department_4 = new SecurityDepartment("E部门");
mainCompany.add(subCompany_0);
mainCompany.add(subCompany_1);
subCompany_0.add(department_0);
subCompany_0.add(department_1);
subCompany_1.add(department_2);
subCompany_1.add(department_3);
subCompany_1.add(department_4);
mainCompany.inform();
}
}
3.优点与缺点
优点:
组合模式的主要优点如下:
(1) 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
(2) 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
(3) 在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合“开闭原则”。
(4) 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。
缺点:
在增加新构件时很难对容器中的构件类型进行限制。有时候我们希望一个容器中只能有某些特定类型的对象,例如在某个文件夹中只能包含文本文件,使用组合模式时,不能依赖类型系统来施加这些约束,因为它们都来自于相同的抽象层,在这种情况下,必须通过在运行时进行类型检查来实现,这个实现过程较为复杂。
4.适用场景
在以下情况下可以考虑使用组合模式:
(1) 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待它们。
(2) 在一个使用面向对象语言开发的系统中需要处理一个树形结构。
(3) 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型。