`

23种设计模式(14):合成模式

 
阅读更多

合成模式属于对象的结构模式,有时又叫做“部分——整体”模式。合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式可以使客户端将单纯元素与复合元素同等看待。

 

合成模式

 

  合成模式把部分和整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由它们复合而成的合成对象同等看待。

  比如,一个文件系统就是一个典型的合成模式系统。下图是常见的计算机XP文件系统的一部分。

 

从上图可以看出,文件系统是一个树结构,树上长有节点。树的节点有两种,一种是树枝节点,即目录,有内部树结构,在图中涂有颜色;另一种是文件,即树叶节点,没有内部树结构。

  显然,可以把目录和文件当做同一种对象同等对待和处理,这也就是合成模式的应用。

  合成模式可以不提供父对象的管理方法,但是合成模式必须在合适的地方提供子对象的管理方法,诸如:add()、remove()、以及getChild()等。

  合成模式的实现根据所实现接口的区别分为两种形式,分别称为安全式透明式

安全式合成模式的结构

  安全模式的合成模式要求管理聚集的方法只出现在树枝构件类中,而不出现在树叶构件类中。

 

这种形式涉及到三个角色:

  ●  抽象构件(Component)角色:这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认行为,可以用来管理所有的子对象。合成对象通常把它所包含的子对象当做类型为Component的对象。在安全式的合成模式里,构件角色并不定义出管理子对象的方法,这一定义由树枝构件对象给出。

  ●  树叶构件(Leaf)角色:树叶对象是没有下级子对象的对象,定义出参加组合的原始对象的行为。

  ●  树枝构件(Composite)角色:代表参加组合的有下级子对象的对象。树枝构件类给出所有的管理子对象的方法,如add()、remove()以及getChild()。

源代码

 抽象构件角色类

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. public interface Component {  
  2.     /** 
  3.      * 输出组建自身的名称 
  4.      */  
  5.     public void printStruct(String preStr);  
  6. }  


树枝构件角色类

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. public class Composite implements Component {  
  2.     /** 
  3.      * 用来存储组合对象中包含的子组件对象 
  4.      */  
  5.     private List<Component> childComponents = new ArrayList<Component>();  
  6.     /** 
  7.      * 组合对象的名字 
  8.      */  
  9.     private String name;  
  10.     /** 
  11.      * 构造方法,传入组合对象的名字 
  12.      * @param name    组合对象的名字 
  13.      */  
  14.     public Composite(String name){  
  15.         this.name = name;  
  16.     }  
  17.     /** 
  18.      * 聚集管理方法,增加一个子构件对象 
  19.      * @param child 子构件对象 
  20.      */  
  21.     public void addChild(Component child){  
  22.         childComponents.add(child);  
  23.     }  
  24.     /** 
  25.      * 聚集管理方法,删除一个子构件对象 
  26.      * @param index 子构件对象的下标 
  27.      */  
  28.     public void removeChild(int index){  
  29.         childComponents.remove(index);  
  30.     }  
  31.     /** 
  32.      * 聚集管理方法,返回所有子构件对象 
  33.      */  
  34.     public List<Component> getChild(){  
  35.         return childComponents;  
  36.     }  
  37.     /** 
  38.      * 输出对象的自身结构 
  39.      * @param preStr 前缀,主要是按照层级拼接空格,实现向后缩进 
  40.      */  
  41.     @Override  
  42.     public void printStruct(String preStr) {  
  43.         // 先把自己输出  
  44.         System.out.println(preStr + "+" + this.name);  
  45.         //如果还包含有子组件,那么就输出这些子组件对象  
  46.         if(this.childComponents != null){<pre name="code" class="java">  

 


树叶构件角色类

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. public class Leaf implements Component {  
  2.     /** 
  3.      * 叶子对象的名字 
  4.      */  
  5.     private String name;  
  6.     /** 
  7.      * 构造方法,传入叶子对象的名称 
  8.      * @param name 叶子对象的名字 
  9.      */  
  10.     public Leaf(String name){  
  11.         this.name = name;  
  12.     }  
  13.     /** 
  14.      * 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字 
  15.      * @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进 
  16.      */  
  17.     @Override  
  18.     public void printStruct(String preStr) {  
  19.         // TODO Auto-generated method stub  
  20.         System.out.println(preStr + "-" + name);  
  21.     }  
  22.   
  23. }  


客户端类

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. public class Client {  
  2.     public static void main(String[]args){  
  3.         Composite root = new Composite("服装");  
  4.         Composite c1 = new Composite("男装");  
  5.         Composite c2 = new Composite("女装");  
  6.           
  7.         Leaf leaf1 = new Leaf("衬衫");  
  8.         Leaf leaf2 = new Leaf("夹克");  
  9.         Leaf leaf3 = new Leaf("裙子");  
  10.         Leaf leaf4 = new Leaf("套装");  
  11.           
  12.         root.addChild(c1);  
  13.         root.addChild(c2);  
  14.         c1.addChild(leaf1);  
  15.         c1.addChild(leaf2);  
  16.         c2.addChild(leaf3);  
  17.         c2.addChild(leaf4);  
  18.           
  19.         root.printStruct("");  
  20.     }  
  21. }  

 

可以看出,树枝构件类(Composite)给出了addChild()、removeChild()以及getChild()等方法的声明和实现,而树叶构件类则没有给出这些方法的声明或实现。这样的做法是安全的做法,由于这个特点,客户端应用程序不可能错误地调用树叶构件的聚集方法,因为树叶构件没有这些方法,调用会导致编译错误。

  安全式合成模式的缺点是不够透明,因为树叶类和树枝类将具有不同的接口。

透明式合成模式的结构

  与安全式的合成模式不同的是,透明式的合成模式要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定接口。



 

源代码

 

  抽象构件角色类

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. public abstract class Component {  
  2.     /** 
  3.      * 输出组建自身的名称 
  4.      */  
  5.     public abstract void printStruct(String preStr);  
  6.     /** 
  7.      * 聚集管理方法,增加一个子构件对象 
  8.      * @param child 子构件对象 
  9.      */  
  10.     public void addChild(Component child){  
  11.         /** 
  12.          * 缺省实现,抛出异常,因为叶子对象没有此功能 
  13.          * 或者子组件没有实现这个功能 
  14.          */  
  15.         throw new UnsupportedOperationException("对象不支持此功能");  
  16.     }  
  17.     /** 
  18.      * 聚集管理方法,删除一个子构件对象 
  19.      * @param index 子构件对象的下标 
  20.      */  
  21.     public void removeChild(int index){  
  22.         /** 
  23.          * 缺省实现,抛出异常,因为叶子对象没有此功能 
  24.          * 或者子组件没有实现这个功能 
  25.          */  
  26.         throw new UnsupportedOperationException("对象不支持此功能");  
  27.     }  
  28.       
  29.     /** 
  30.      * 聚集管理方法,返回所有子构件对象 
  31.      */  
  32.     public List<Component> getChild(){  
  33.         /** 
  34.          * 缺省实现,抛出异常,因为叶子对象没有此功能 
  35.          * 或者子组件没有实现这个功能 
  36.          */  
  37.         throw new UnsupportedOperationException("对象不支持此功能");  
  38.     }  
  39. }  


树枝构件角色类,此类将implements Conponent改为extends Conponent,其他地方无变化。

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. public class Composite extends Component {  
  2.     /** 
  3.      * 用来存储组合对象中包含的子组件对象 
  4.      */  
  5.     private List<Component> childComponents = new ArrayList<Component>();  
  6.     /** 
  7.      * 组合对象的名字 
  8.      */  
  9.     private String name;  
  10.     /** 
  11.      * 构造方法,传入组合对象的名字 
  12.      * @param name    组合对象的名字 
  13.      */  
  14.     public Composite(String name){  
  15.         this.name = name;  
  16.     }  
  17.     /** 
  18.      * 聚集管理方法,增加一个子构件对象 
  19.      * @param child 子构件对象 
  20.      */  
  21.     public void addChild(Component child){  
  22.         childComponents.add(child);  
  23.     }  
  24.     /** 
  25.      * 聚集管理方法,删除一个子构件对象 
  26.      * @param index 子构件对象的下标 
  27.      */  
  28.     public void removeChild(int index){  
  29.         childComponents.remove(index);  
  30.     }  
  31.     /** 
  32.      * 聚集管理方法,返回所有子构件对象 
  33.      */  
  34.     public List<Component> getChild(){  
  35.         return childComponents;  
  36.     }  
  37.     /** 
  38.      * 输出对象的自身结构 
  39.      * @param preStr 前缀,主要是按照层级拼接空格,实现向后缩进 
  40.      */  
  41.     @Override  
  42.     public void printStruct(String preStr) {  
  43.         // 先把自己输出  
  44.         System.out.println(preStr + "+" + this.name);  
  45.         //如果还包含有子组件,那么就输出这些子组件对象  
  46.         if(this.childComponents != null){  
  47.             //添加两个空格,表示向后缩进两个空格  
  48.             preStr += "  ";  
  49.             //输出当前对象的子对象  
  50.             for(Component c : childComponents){  
  51.                 //递归输出每个子对象  
  52.                 c.printStruct(preStr);  
  53.             }  
  54.         }  
  55.           
  56.     }  
  57.   
  58. }  


树叶构件角色类,此类将implements Conponent改为extends Conponent,其他地方无变化。

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. public class Leaf extends Component {  
  2.     /** 
  3.      * 叶子对象的名字 
  4.      */  
  5.     private String name;  
  6.     /** 
  7.      * 构造方法,传入叶子对象的名称 
  8.      * @param name 叶子对象的名字 
  9.      */  
  10.     public Leaf(String name){  
  11.         this.name = name;  
  12.     }  
  13.     /** 
  14.      * 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字 
  15.      * @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进 
  16.      */  
  17.     @Override  
  18.     public void printStruct(String preStr) {  
  19.         // TODO Auto-generated method stub  
  20.         System.out.println(preStr + "-" + name);  
  21.     }  
  22.   
  23. }  


客户端类的主要变化是不再区分Composite对象和Leaf对象。

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. public class Client {  
  2.     public static void main(String[]args){  
  3.         Component root = new Composite("服装");  
  4.         Component c1 = new Composite("男装");  
  5.         Component c2 = new Composite("女装");  
  6.           
  7.         Component leaf1 = new Leaf("衬衫");  
  8.         Component leaf2 = new Leaf("夹克");  
  9.         Component leaf3 = new Leaf("裙子");  
  10.         Component leaf4 = new Leaf("套装");  
  11.           
  12.         root.addChild(c1);  
  13.         root.addChild(c2);  
  14.         c1.addChild(leaf1);  
  15.         c1.addChild(leaf2);  
  16.         c2.addChild(leaf3);  
  17.         c2.addChild(leaf4);  
  18.           
  19.         root.printStruct("");  
  20.     }  
  21. }  

 

可以看出,客户端无需再区分操作的是树枝对象(Composite)还是树叶对象(Leaf)了;对于客户端而言,操作的都是Component对象。

两种实现方法的选择

  这里所说的安全性合成模式是指:从客户端使用合成模式上看是否更安全,如果是安全的,那么就不会有发生误操作的可能,能访问的方法都是被支持的。

  这里所说的透明性合成模式是指:从客户端使用合成模式上,是否需要区分到底是“树枝对象”还是“树叶对象”。如果是透明的,那就不用区分,对于客户而言,都是Compoent对象,具体的类型对于客户端而言是透明的,是无须关心的。

  对于合成模式而言,在安全性和透明性上,会更看重透明性,毕竟合成模式的目的是:让客户端不再区分操作的是树枝对象还是树叶对象,而是以一个统一的方式来操作。

  而且对于安全性的实现,需要区分是树枝对象还是树叶对象。有时候,需要将对象进行类型转换,却发现类型信息丢失了,只好强行转换,这种类型转换必然是不够安全的。

  因此在使用合成模式的时候,建议多采用透明性的实现方式。 

分享到:
评论

相关推荐

    浅析23种软件设计模式

    浅析23种软件设计模式 软件设计模式是软件开发中的一种解决方案,旨在解决软件设计中的各种问题。下面我们将对23种常见的软件设计模式进行浅析。 1. 工厂模式:工厂模式的主要思想是将客户类和工厂类分开,客户类...

    设计模式精解-GoF 23种设计模式解析附C++实现源码

    ### 设计模式精解——GoF 23种设计模式解析及C++实现源码 #### 引言 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。GoF(Gang of Four)所提出的23种设计模式,被认为是面向对象...

    C++ Design Pattern 23种设计模式(全_解释+源代码).zip

    在这个"C++ Design Pattern 23种设计模式(全_解释+源代码).zip"压缩包中,包含了对23种经典设计模式的详细解释和源代码实现,这些模式均基于面向对象编程的原则。 首先,我们来看看这些设计模式的基础原则: 1. **...

    23种设计模式(C++)

    在C++等编程语言中,23种设计模式被广泛研究和应用,它们被分为创建型模式、结构型模式和行为模式三大类。 创建型模式主要涉及对象的创建,它们隐藏了对象创建的细节,通过创建接口隐藏了实例化的细节。它们包括: ...

    Java中23种设计模式详解

    Java 中 23 种设计模式详解 在软件设计中,设计模式是解决特定问题的通用解决方案。 Java 中有 23 种常见的设计模式,下面将对每种设计模式进行详细的解释: 1. 抽象工厂模式(Abstract Factory) 抽象工厂模式...

    23种设计模式

    【设计模式概述】 设计模式是软件工程中的一种最佳实践,它是为了解决在...以上内容是对23种设计模式的简要介绍,实际应用中,开发者需要根据项目需求选择合适的设计模式,灵活组合,以实现高效、可维护的代码结构。

    编程的23种设计模式(mm设计模式,形象易懂)

    以下是23种设计模式中的几个关键概念,结合MM的比喻进行解释: 1. **工厂模式**:就像在麦当劳或肯德基点餐,你只需要告诉服务员你想要什么,无需关心食物是如何制作的。在编程中,工厂模式隐藏了对象创建的复杂性...

    C#23种设计模式_示例源代码及PDF

    合成模式:合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式就 合成模式 是一个处理对象的树结构的模式。 合成模式把部分与整体的关系用树结构表示出来。 合成模 式使得客户端把一个个单独的...

    23种设计模式.pdf

    23种设计模式是软件工程领域的重要组成部分,它们按照功能和用途可以分为三大类:创建型模式、结构型模式和行为型模式。 创建型模式关注对象的创建,包括: 1. 工厂方法模式:提供一个创建对象的接口,让子类决定...

    Java中的23种设计模式.doc

    Java中的23种设计模式是软件开发中常用的设计思想,它们可以帮助我们构建更加灵活、可维护和可扩展的代码。以下是对这些模式的详细说明: 1. 工厂模式:这是最基础的设计模式之一,主要用于对象的创建。它提供了一...

    Java 23种设计模式通解

    "Java 23种设计模式通解" 本文档总结了Java 23种设计模式的基本概念、分类、六大原则和详细实现。设计模式是软件工程的基石,它们被广泛应用于软件开发中,以提高代码的可重用性、可读性和可维护性。 设计模式的...

    23种设计模式.doc

    以下是23种设计模式的一些解释: 1. **工厂模式**:工厂模式是一种创建型设计模式,它提供了一个创建对象的接口,但允许子类决定实例化哪一个类。这样,工厂模式可以使代码独立于具体的产品实现。 2. **建造者模式...

    23种设计模式全解析.pdf

    23种设计模式按其功能和应用场景可以分为三大类:创建型模式、结构型模式和行为型模式。 创建型模式主要与对象的创建有关,共有五种: 1. 工厂方法模式(Factory Method):定义一个创建对象的接口,但由子类决定要...

    23种JAVA设计模式和15种J2EE设计模式 高清完整PDF版

    23种JAVA设计模式按照其目的和范畴可以分为三大类:创建型模式、结构型模式和行为型模式。接下来我会详细介绍这些模式。 创建型模式主要用于创建对象,隐藏创建逻辑而不是用新的代码来直接实例化对象,这样可以提高...

    java23种设计模式

    Java中的23种设计模式是软件开发中常用的设计思想,它们可以帮助我们构建可维护、可扩展的代码。以下是对每种设计模式的详细说明: 1. 工厂模式:这是一种创建型模式,它提供了一种创建对象的最佳方式,将对象的...

    23种设计模式趣味讲解

    在本文中,我们将深入探讨23种设计模式中的部分,主要集中在创立型和结构型模式,这些模式有助于提高代码的灵活性、可维护性和可扩展性。 ### 创立型模式 1. **工厂模式**: 工厂模式是一种简单的创建对象的方式...

    JAVA设计模式-原则和23种设计模式归纳总结

    JAVA设计模式-原则和23种设计模式归纳总结 本资源主要介绍了JAVA设计模式的原则和23种设计模式的总结。设计模式是软件设计中的一种解决方案,能够使软件系统更加灵活、可维护和可扩展。本资源首先介绍了设计模式的...

    java23个设计模式

    Java的23种设计模式被广泛应用于各种项目中,以提高代码的可读性、可维护性和可扩展性。 首先,设计模式可以分为三大类: 1. 创建型模式: - 工厂方法模式:提供一个创建对象的接口,但由子类决定要实例化的类。 ...

    Java之23种设计模式解析

    ### Java之23种设计模式解析 #### 一、设计模式概述 设计模式是软件工程领域内的一种经验总结,它们是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式能够帮助解决常见的设计问题,...

Global site tag (gtag.js) - Google Analytics