一、组合模式概述
组合模式的定义与意图:将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。(对象结构型)
-
组合模式分析:
- 1.当容器对象的某一个方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员对象并调用执行,牵一而动百,其中使用了递归调用的机制来对整个结构进行处理;
- 2.由于容器对象和叶子对象在功能上的区别,在使用这些对象的代码中必须有区别地对待容器对象和叶子对象,而实际上大多数情况下客户端希望一致地处理它们,因为对于这些对象的区别对待将会使程序非常复杂。
-
如何一致地对待容器对象和叶子对象?
- 组合模式通过一种巧妙地设计方案使得用户可以一致性地处理整个树形结构或者树形结构地一部分,它描述了如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须对它进行区分,可以一致地对待容器对象和叶子对象。
-
安全组合模式:
- 1.抽象构件Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法;
- 2.对于叶子对象,客户端不可能调用到这些方法;
- 3.缺点是不够透明,客户端不能完全针对抽象编程。必须有区别地对待叶子构件和容器构件。
-
透明组合模式:
- 1.抽象构件Component中声明了所有用于管理成员对象的方法,包括add()、remove()、以及getChild()等方法;
- 2.在客户端看来,叶子对象与容器对象所提供的方法是一致的,客户端可以一致地对待所有的对象;
- 3.缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的。
-
组合模式的优缺点:
-
优点:
- 1.可以清楚的定义分层次的复杂对象,表示对象的全部或部分层次,让客户端忽略了层次的差异,方便对整个层次结构将进行控制;
- 2.客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码;
- 3.增加新的容器构件和叶子构件都很方便,符合开闭原则;
- 4.为树形结构的面向对象实现提供了一种灵活的解决方案。
-
缺点:
- 在增加新构件时很难对容器中的构件类型进行限制。
-
优点:
-
适用环境:
- 1.在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待他们;
- 2.在一个使用面向对象语言开发的系统中需要处理一个树形结构;
- 3.在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型。
二、代码实现
组合模式的结构:
- Component(抽象构件)
- Leaf(叶子构件)
- Composite(容器构件)
某教育机构组织结构如下图所示:
在该教育机构的OA系统中可以给各级办公室下发公文,试采用组合模式设计该机构的组织结构,绘制相应的类图并编程模拟实现,在客户端代码中模拟下发公文。
2.1 Component(抽象构件类:AbstractHead)
package composite.OAteacher;
//(1)Component抽象构件类:AbstractHead
public abstract class AbstractHead {
public abstract void receiveDocument();
}
2.2 Leaf(叶子构件:AdminOffice、ProvostOffice)
package composite.OAteacher;
//(2.1)Leaf叶子构件类:AdminOffice
public class AdminOffice extends AbstractHead {
private String officeName;
public AdminOffice(String officeName){
this.officeName = officeName;
}
public void receiveDocument(){
System.out.println(officeName + "收到文件");
}
}
package composite.OAteacher;
//(2.2)Leaf叶子构件类:ProvostOffice
public class ProvostOffice extends AbstractHead {
private String officeName;
public ProvostOffice(String officeName){
this.officeName = officeName;
}
public void receiveDocument(){
System.out.println(this.officeName + "收到文件...");
}
}
2.3 Composite(容器构件:Branch,定义构件行为)
package composite.OAteacher;
import java.util.*;
//(3)composite:定义组件行为,比如下发文件动作
public class Branch extends AbstractHead {
private String branchName;
ArrayList list = new ArrayList();
public Branch(String branchName){
this.branchName = branchName;
}
public void addSubOrg(AbstractHead elment){
list.add(elment);
}
public void removeSubOrg(AbstractHead element){
list.remove(element);
}
public void receiveDocument(){
System.out.println("-----------------------------------------");
for(Object object: list){
//System.out.println(object.getClass());
if(object.getClass().toString().equals("class Branch"))
{
((Branch)object).issudedDocument();
}
else
((AbstractHead)object).receiveDocument();
}
}
public void issudedDocument(){
System.out.println(branchName + "下发文件......");
this.receiveDocument();
}
}
2.4 main方法实现组合模式
package composite.OAteacher;
//(5)客户端测试类:Client
/*
* 题目:
某教育机构组织结构如下图所示:
在该教育机构的OA系统中可以给各级办公室下发公文,现采用组合模式设计该机构的组织结构,绘制相应的类图并编程模拟实现,在客户端代码中模拟下发公文。
*/
public class Client {
public static void main(String args[]){
AbstractHead office11 = new ProvostOffice("长沙教学点教务办公室");
AbstractHead office12 = new ProvostOffice("长沙教学点行政办公室");
Branch b1 = new Branch("长沙教学点");
b1.addSubOrg(office11);
b1.addSubOrg(office12);
AbstractHead office21 = new ProvostOffice("湘潭教学点教务办公室");
AbstractHead office22 = new ProvostOffice("湘潭教学点行政办公室");
Branch b2 = new Branch("湘潭教学点");
b2.addSubOrg(office21);
b2.addSubOrg(office22);
AbstractHead office31 = new ProvostOffice("湖南分校教务办公室");
AbstractHead office32 = new ProvostOffice("湖南分校行政办公室");
Branch b3 = new Branch("湖南分校");
b3.addSubOrg(office31);
b3.addSubOrg(office32);
b3.addSubOrg(b1);
b3.addSubOrg(b2);
AbstractHead office41 = new ProvostOffice("北京总部教务办公室");
AbstractHead office42 = new ProvostOffice("北京总部行政办公室");
Branch b4 = new Branch("北京总部");
b4.addSubOrg(office41);
b4.addSubOrg(office42);
b4.addSubOrg(b3);
b4.issudedDocument();
//b4.receiveDocument();
}
}