设计模式系列 - 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:

申明接口:

 
  1. public interface Component { 
  2.     public void doSomething(); 

 具体实现:

 
  1. public class Leaf implements Component{ 
  2.  
  3.     @Override 
  4.     public void doSomething() { 
  5.         // TODO Auto-generated method stub 
  6.         System.out.println("执行方法.."); 
  7.     } 
  8.  

 组合:

 
  1. public class Composite implements Component { 
  2.     public List<Component> components = new ArrayList<Component>(); 
  3.  
  4.     public void add(Component component) { 
  5.         components.add(component); 
  6.     } 
  7.  
  8.     public void remove(Component component) { 
  9.         components.remove(component); 
  10.     } 
  11.  
  12.     public List<Component> getAll() { 
  13.         return components; 
  14.     } 
  15.  
  16.     @Override 
  17.     public void doSomething() { 
  18.         // TODO Auto-generated method stub 
  19.         for (Component component : components) { 
  20.             component.doSomething(); 
  21.         } 
  22.     } 
  23.  

测试:

 
  1. public static void main(String[] args) { 
  2.       Component leaf1 = new Leaf(); 
  3.       Component leaf2 = new Leaf(); 
  4.  
  5.       Composite composite1 = new Composite(); 
  6.       composite1.add(leaf1); 
  7.       composite1.add(leaf2); 
  8.  
  9.       Component leaf3 = new Leaf(); 
  10.       Component leaf4 = new Leaf(); 
  11.  
  12.       Composite composite2 = new Composite(); 
  13.       composite2.add(composite1); 
  14.       composite2.add(leaf3); 
  15.       composite2.add(leaf4); 
  16.  
  17.       composite2.doSomething(); 
  18.   } 

实现方式2:

各方法升级到接口中完成:

 
  1. public interface Component { 
  2.  
  3.     public void doSomething(); 
  4.  
  5.     public void add(Component component); 
  6.  
  7.     public void remove(Component component); 
  8.  
  9.     public List<Component> getAll(); 

叶子节点Leaf 除了做事情外,其他为空实现

 
  1. public class Leaf implements Component { 
  2.  
  3.     @Override 
  4.     public void doSomething() { 
  5.         // TODO Auto-generated method stub 
  6.         System.out.println("do things..."); 
  7.     } 
  8.  
  9.     @Override 
  10.     public void add(Component component) { 
  11.         // TODO Auto-generated method stub 
  12.  
  13.     } 
  14.  
  15.     @Override 
  16.     public void remove(Component component) { 
  17.         // TODO Auto-generated method stub 
  18.  
  19.     } 
  20.  
  21.     @Override 
  22.     public List<Component> getAll() { 
  23.         // TODO Auto-generated method stub 
  24.         return null
  25.     } 
  26.  

 

 
  1. public class Composite implements Component { 
  2.     private List<Component> components = new ArrayList<Component>(); 
  3.  
  4.     @Override 
  5.     public void doSomething() { 
  6.         // TODO Auto-generated method stub 
  7.         for (Component component : components) { 
  8.             component.doSomething(); 
  9.         } 
  10.     } 
  11.  
  12.     @Override 
  13.     public void add(Component component) { 
  14.         // TODO Auto-generated method stub 
  15.         components.add(component); 
  16.     } 
  17.  
  18.     @Override 
  19.     public void remove(Component component) { 
  20.         // TODO Auto-generated method stub 
  21.         components.remove(component); 
  22.     } 
  23.  
  24.     @Override 
  25.     public List<Component> getAll() { 
  26.         // TODO Auto-generated method stub 
  27.         return components; 
  28.     } 
  29.  

 测试:测试方式和方式1相同

 


本文转自 zhouhaipeng 51CTO博客,原文链接:http://blog.51cto.com/tianya23/708657,如需转载请自行联系原作者


相关文章
|
15天前
|
设计模式 SQL 算法
设计模式了解哪些,模版模式
设计模式了解哪些,模版模式
19 0
|
1月前
|
设计模式 Java uml
C++设计模式之 依赖注入模式探索
C++设计模式之 依赖注入模式探索
37 0
|
3月前
|
设计模式 存储 算法
Java 设计模式最佳实践:三、行为模式
Java 设计模式最佳实践:三、行为模式
22 0
|
3月前
|
设计模式 Go 开发工具
Golang设计模式——12中介模式
Golang设计模式——12中介模式
26 0
|
2月前
|
设计模式 前端开发 JavaScript
观察者模式 vs 发布-订阅模式:两种设计模式的对决!
欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。
|
11天前
|
设计模式 Java 数据库
小谈设计模式(2)—简单工厂模式
小谈设计模式(2)—简单工厂模式
|
1天前
|
设计模式
设计模式(一)简单工厂模式
设计模式(一)简单工厂模式
4 0
|
11天前
|
设计模式 Java
小谈设计模式(9)—工厂方法模式
小谈设计模式(9)—工厂方法模式
|
1月前
|
设计模式 编译器
解析器模式--设计模式
解析器模式--设计模式
17 0
|
1月前
|
设计模式 算法
构建器模式--设计模式
构建器模式--设计模式
17 0