设计模式系列 - Composite模式
1、定义与结构
组合(Composite)模式的其它翻译名称也很多,比如合成模式、树模式等等。在《设计模式》一书中给出的定义是:将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。
从定义中可以得到使用组合模式的环境为:在设计中想表示对象的“部分-整体”层次结构;希望用户忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象。
看下组合模式的组成。
1) 抽象构件角色Component:它为组合中的对象声明接口,也可以为共有接口实现缺省行为。
2) 树叶构件角色Leaf:在组合中表示叶节点对象——没有子节点,实现抽象构件角色声明的接口。
3) 树枝构件角色Composite:在组合中表示分支节点对象——有子节点,实现抽象构件角色声明的接口;存储子部件。
下图为组合模式的类图表示。
如图所示:一个Composite实例可以像一个简单的Leaf实例一样,可以把它传递给任何使用Component的方法或者对象,并且它表现的就像是一个Leaf一样。
可以看出来,使用组合模式使得这个设计结构非常灵活,在下面的例子中会得到进一步的印证。
2、安全性与透明性
组合模式中必须提供对子对象的管理方法,不然无法完成对子对象的添加删除等等操作,也就失去了灵活性和扩展性。但是管理方法是在Component中就声明还是在Composite中声明呢?
一种方式是在Component里面声明所有的用来管理子类对象的方法,以达到Component接口的最大化(如下图所示)。目的就是为了使客户看来在接口层次上树叶和分支没有区别——透明性。但树叶是不存在子类的,因此Component声明的一些方法对于树叶来说是不适用的。这样也就带来了一些安全性问题。
另一种方式就是只在Composite里面声明所有的用来管理子类对象的方法(如下图所示)。这样就避免了上一种方式的安全性问题,但是由于叶子和分支有不同的接口,所以又失去了透明性。
《设计模式》一书认为:在这一模式中,相对于安全性,我们比较强调透明性。对于第一种方式中叶子节点内不需要的方法可以使用空处理或者异常报告的方式来解决。
3、举例
这里以JUnit中的组合模式的应用为例(JUnit入门)。
JUnit是一个单元测试框架,按照此框架下的规范来编写测试代码,就可以使单元测试自动化。为了达到“自动化”的目的,JUnit中定义了两个概念:TestCase和TestSuite。TestCase是对一个类或者jsp等等编写的测试类;而TestSuite是一个不同TestCase的集合,当然这个集合里面也可以包含TestSuite元素,这样运行一个TestSuite会将其包含的TestCase全部运行。
然而在真实运行测试程序的时候,是不需要关心这个类是TestCase还是TestSuite,我们只关心测试运行结果如何。这就是为什么JUnit使用组合模式的原因。
JUnit为了采用组合模式将TestCase和TestSuite统一起来,创建了一个Test接口来扮演抽象构件角色,这样原来的TestCase扮演组合模式中树叶构件角色,而TestSuite扮演组合模式中的树枝构件角色。
4、代码:
实现方式1:
申明接口:
- public interface Component {
- public void doSomething();
- }
具体实现:
- public class Leaf implements Component{
- @Override
- public void doSomething() {
- // TODO Auto-generated method stub
- System.out.println("执行方法..");
- }
- }
组合:
- public class Composite implements Component {
- public List<Component> components = new ArrayList<Component>();
- public void add(Component component) {
- components.add(component);
- }
- public void remove(Component component) {
- components.remove(component);
- }
- public List<Component> getAll() {
- return components;
- }
- @Override
- public void doSomething() {
- // TODO Auto-generated method stub
- for (Component component : components) {
- component.doSomething();
- }
- }
- }
测试:
- public static void main(String[] args) {
- Component leaf1 = new Leaf();
- Component leaf2 = new Leaf();
- Composite composite1 = new Composite();
- composite1.add(leaf1);
- composite1.add(leaf2);
- Component leaf3 = new Leaf();
- Component leaf4 = new Leaf();
- Composite composite2 = new Composite();
- composite2.add(composite1);
- composite2.add(leaf3);
- composite2.add(leaf4);
- composite2.doSomething();
- }
实现方式2:
各方法升级到接口中完成:
- public interface Component {
- public void doSomething();
- public void add(Component component);
- public void remove(Component component);
- public List<Component> getAll();
- }
叶子节点Leaf :除了做事情外,其他为空实现
- public class Leaf implements Component {
- @Override
- public void doSomething() {
- // TODO Auto-generated method stub
- System.out.println("do things...");
- }
- @Override
- public void add(Component component) {
- // TODO Auto-generated method stub
- }
- @Override
- public void remove(Component component) {
- // TODO Auto-generated method stub
- }
- @Override
- public List<Component> getAll() {
- // TODO Auto-generated method stub
- return null;
- }
- }
- public class Composite implements Component {
- private List<Component> components = new ArrayList<Component>();
- @Override
- public void doSomething() {
- // TODO Auto-generated method stub
- for (Component component : components) {
- component.doSomething();
- }
- }
- @Override
- public void add(Component component) {
- // TODO Auto-generated method stub
- components.add(component);
- }
- @Override
- public void remove(Component component) {
- // TODO Auto-generated method stub
- components.remove(component);
- }
- @Override
- public List<Component> getAll() {
- // TODO Auto-generated method stub
- return components;
- }
- }
测试:测试方式和方式1相同
本文转自 zhouhaipeng 51CTO博客,原文链接:http://blog.51cto.com/tianya23/708657,如需转载请自行联系原作者