组合模式
摘要
本文通过简洁的模式描述,应用场景的详细代码实现,以及匹配的UML,详解介绍了组合模式的原理及应用。本文可帮助读者快速掌握组合模式,以便工作学习中使用组合模式。
一、组合模式
在我们的生活中,很多事物都有一个组织架构的分层现象。比如一个国家的组织结构:国家–省份–市--县–镇--村–人,其中除国家是唯一对象之外,其它部分都是多个对象实体;再比如一个集团的组织架构:集团–一级公司–二级公司–部门–小组–程序员,同样,除集团是唯一对象之外,其它部分都可以是多个实体。这两个例子中还有一个共同的特点,他们的组织架构中最后一个对象都是不可再分的,不会再有子组织结构。
在组织结构中,如果上层有消息需要通知到最底层时,每一层的任务都是将消息通知到下一层,比如集团级只与一级公司交互,再由一级公司与二级公司交互,由此类推,一直到小组与程序员交互,在这个交互的过程中,集团并没有与程序员直接交互,所以实现了集团与程序员之间的解耦操作,方便了其内部组织结构的变动,如程序员换了一批人,从组织架构、公司运行上来说并没有什么影响。同样,单个部门换掉,也不会导致该组织架构的大量改动,保证了“开闭原则”,也体现了“职责单一原则”,只是部门级以下的成员会受到影响,他们将不再接收到上级的消息,或将他们转入其它部门。
在程序的世界里,有一种熟悉的数据结构——树,树结构就类似于上面组织结构。根节点只有一个,可以有多个子节点,也可以多个叶节点,但叶节点不能有子节点或子叶节点。组合模式将各个对象的之间的组织结构封装起来,一是为了保证组织架构不会被破坏,二是为了方便第三方的使用,第三方不用清楚组织架构是怎样,他只需要对某个节点进行操作。
二、组合模式的实现
2.1 场景设计
对于组合模式,暂没有想到身边的具体实例,所以本文就以节点和叶节点的命名方式来实现组合模式。从上面的解析中可知:根节点只有一个,可以有多个子节点,也可以多个叶节点,但叶节点不能有子节点或子叶节点。所以节点可以看成是一个容器。在消息的传送中,节点和叶节点都能收到消息,所以他们又具有相同的功能,所以节点和叶节点可以共同继承与一个共同的接口或抽象类。
2.2 代码实现
2.2.1 Component 抽象
package ft.patterns.composite;
import java.util.ArrayList;
import java.util.List;
public abstract class Component {
public Component() {
this.leafList = new ArrayList<Component>();
}
List<Component> leafList;
void add(Component leaf){
throw new UnsupportedOperationException();
};
boolean remove(Component leaf) {
throw new UnsupportedOperationException();
};
void execute() {
throw new UnsupportedOperationException();
}
}
2.2.2 Composite 节点类
package ft.patterns.composite;
import java.util.ArrayList;
import java.util.List;
public class Composite extends Component{
private String name;
private List<Component> componentList;
public Composite(String name) {
super();
this.name = name;
componentList = new ArrayList<Component>();
}
@Override
void add(Component leaf) {
if(leaf != null)
componentList.add(leaf);
}
@Override
boolean remove(Component leaf) {
int result = componentList.indexOf(leaf);
if(result != -1) {
componentList.remove(result);
return true;
}
return false;
}
@Override
void execute() {
System.out.println("hello "+name);
for(Component temp : componentList) {
temp.execute();
}
}
}
2.2.3 Leaf 叶节点类
package ft.patterns.composite;
public class Leaf extends Component{
private String name;
public Leaf(String name){
super();
this.name = name;
}
@Override
void execute() {
System.out.println("hello " + name);
}
}
2.2.4 Main 测试类
package ft.patterns.composite;
public class Main {
public static void main(String[] args) {
Component root = new Composite("root");
Component leaf1 = new Leaf("leaf1");
Component leaf2 = new Leaf("leaf2");
Component component1 = new Composite("component1");
Component leaf3 = new Leaf("leaf3");
Component leaf4 = new Leaf("leaf4");
Component leaf5 = new Leaf("leaf5");
Component component2 = new Composite("component2");
Component leaf6 = new Leaf("leaf6");
Component component3 = new Composite("component3");
component3.add(leaf3);
component3.add(leaf4);
component1.add(leaf2);
component1.add(component3);
component2.add(leaf5);
component2.add(leaf6);
root.add(component1);
root.add(component2);
root.add(leaf1);
System.out.println("########################");
root.execute();
System.out.println("########################");
component1.execute();
System.out.println("########################");
component3.execute();
System.out.println("########################");
component2.execute();
}
}
2.2.5 测试结果
########################
hello root
hello component1
hello leaf2
hello component3
hello leaf3
hello leaf4
hello component2
hello leaf5
hello leaf6
hello leaf1
########################
hello component1
hello leaf2
hello component3
hello leaf3
hello leaf4
########################
hello component3
hello leaf3
hello leaf4
########################
hello component2
hello leaf5
hello leaf6