java设计模式组合模式详解_《JAVA设计模式》之组合模式(Composite)

在阎宏博士的《JAVA与模式》一书中开头是这样描述合成(Composite)模式的:html

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

合成模式

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

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

091b64f3d4c046f2be62ef7c.html

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

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

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

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

安全式合成模式的结构

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

091b64f3d4c046f2be62ef7c.html.net

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

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

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

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

源代码

抽象构件角色类

public interfaceComponent {

/*** 输出组建自身的名称 */ public voidprintStruct(String preStr); }

树枝构件角色类

public class Composite implementsComponent {

/*** 用来存储组合对象中包含的子组件对象 */ private List childComponents = new ArrayList(); /*** 组合对象的名字 */ privateString name; /*** 构造方法,传入组合对象的名字 * @paramname 组合对象的名字 */ publicComposite(String name){ this.name =name; } /*** 汇集管理方法,增长一个子构件对象 * @paramchild 子构件对象 */ public voidaddChild(Component child){ childComponents.add(child); } /*** 汇集管理方法,删除一个子构件对象 * @paramindex 子构件对象的下标 */ public void removeChild(intindex){ childComponents.remove(index); } /*** 汇集管理方法,返回全部子构件对象 */ public ListgetChild(){ returnchildComponents; } /*** 输出对象的自身结构 * @parampreStr 前缀,主要是按照层级拼接空格,实现向后缩进 */@Override public voidprintStruct(String preStr) { //先把本身输出 System.out.println(preStr + "+" + this.name); //若是还包含有子组件,那么就输出这些子组件对象 if(this.childComponents != null){ //添加两个空格,表示向后缩进两个空格 preStr += " "; //输出当前对象的子对象 for(Component c : childComponents){ //递归输出每一个子对象 c.printStruct(preStr); } } } }

树叶构件角色类

public class Leaf implementsComponent {

/*** 叶子对象的名字 */ privateString name; /*** 构造方法,传入叶子对象的名称 * @paramname 叶子对象的名字 */ publicLeaf(String name){ this.name =name; } /*** 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字 * @parampreStr 前缀,主要是按照层级拼接的空格,实现向后缩进 */@Override public voidprintStruct(String preStr) { //TODO Auto-generated method stub System.out.println(preStr + "-" +name); } }

客户端类

public classClient {

public static voidmain(String[]args){ Composite root = new Composite("服装"); Composite c1 = new Composite("男装"); Composite c2 = new Composite("女装"); Leaf leaf1 = new Leaf("衬衫"); Leaf leaf2 = new Leaf("夹克"); Leaf leaf3 = new Leaf("裙子"); Leaf leaf4 = new Leaf("套装"); root.addChild(c1); root.addChild(c2); c1.addChild(leaf1); c1.addChild(leaf2); c2.addChild(leaf3); c2.addChild(leaf4); root.printStruct(""); } }

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

安全式合成模式的缺点是不够透明,由于树叶类和树枝类将具备不一样的接口。

透明式合成模式的结构

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

091b64f3d4c046f2be62ef7c.html

源代码

抽象构件角色类

public abstract classComponent {

/*** 输出组建自身的名称 */ public abstract voidprintStruct(String preStr); /*** 汇集管理方法,增长一个子构件对象 * @paramchild 子构件对象 */ public voidaddChild(Component child){ /*** 缺省实现,抛出异常,由于叶子对象没有此功能 * 或者子组件没有实现这个功能 */ throw new UnsupportedOperationException("对象不支持此功能"); } /*** 汇集管理方法,删除一个子构件对象 * @paramindex 子构件对象的下标 */ public void removeChild(intindex){ /*** 缺省实现,抛出异常,由于叶子对象没有此功能 * 或者子组件没有实现这个功能 */ throw new UnsupportedOperationException("对象不支持此功能"); } /*** 汇集管理方法,返回全部子构件对象 */ public ListgetChild(){ /*** 缺省实现,抛出异常,由于叶子对象没有此功能 * 或者子组件没有实现这个功能 */ throw new UnsupportedOperationException("对象不支持此功能"); } }

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

public class Composite extendsComponent {

/*** 用来存储组合对象中包含的子组件对象 */ private List childComponents = new ArrayList(); /*** 组合对象的名字 */ privateString name; /*** 构造方法,传入组合对象的名字 * @paramname 组合对象的名字 */ publicComposite(String name){ this.name =name; } /*** 汇集管理方法,增长一个子构件对象 * @paramchild 子构件对象 */ public voidaddChild(Component child){ childComponents.add(child); } /*** 汇集管理方法,删除一个子构件对象 * @paramindex 子构件对象的下标 */ public void removeChild(intindex){ childComponents.remove(index); } /*** 汇集管理方法,返回全部子构件对象 */ public ListgetChild(){ returnchildComponents; } /*** 输出对象的自身结构 * @parampreStr 前缀,主要是按照层级拼接空格,实现向后缩进 */@Override public voidprintStruct(String preStr) { //先把本身输出 System.out.println(preStr + "+" + this.name); //若是还包含有子组件,那么就输出这些子组件对象 if(this.childComponents != null){ //添加两个空格,表示向后缩进两个空格 preStr += " "; //输出当前对象的子对象 for(Component c : childComponents){ //递归输出每一个子对象 c.printStruct(preStr); } } } }

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

public class Leaf extendsComponent {

/*** 叶子对象的名字 */ privateString name; /*** 构造方法,传入叶子对象的名称 * @paramname 叶子对象的名字 */ publicLeaf(String name){ this.name =name; } /*** 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字 * @parampreStr 前缀,主要是按照层级拼接的空格,实现向后缩进 */@Override public voidprintStruct(String preStr) { //TODO Auto-generated method stub System.out.println(preStr + "-" +name); } }

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

public classClient {

public static voidmain(String[]args){ Component root = new Composite("服装"); Component c1 = new Composite("男装"); Component c2 = new Composite("女装"); Component leaf1 = new Leaf("衬衫"); Component leaf2 = new Leaf("夹克"); Component leaf3 = new Leaf("裙子"); Component leaf4 = new Leaf("套装"); root.addChild(c1); root.addChild(c2); c1.addChild(leaf1); c1.addChild(leaf2); c2.addChild(leaf3); c2.addChild(leaf4); root.printStruct(""); } }

能够看出,客户端无需再区分操做的是树枝对象(Composite)仍是树叶对象(Leaf)了;对于客户端而言,操做的都是Component对象。

两种实现方法的选择

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

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/550002.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

XAF Excel数据导入模块使用说明与源码

我实现了XAF项目中Excel数据的导入,使用Devexpress 新出的spreadsheet控件,可能也不新了吧:D 好,先看一下效果图:下图是Web版本的。 下面是win版: 功能说明: 支持从Excel任意版本导入数据,可以使…

ASP注入漏洞基础教程(二)

进 阶 篇 在入门篇,我们学会了SQL注入的判断方法,但真正要拿到网站的保密内容,是远远不够的。接下来,我们就继续学习如何从数据库中获取想要获得的内容,首先,我们先看看&…

linux 内存清理/释放命令

1.清理前内存使用情况 free -m2.开始清理 echo 1 > /proc/sys/vm/drop_caches3.清理后内存使用情况 free -m4.完成!查看内存条数命令: dmidecode | grep -A16 "Memory Device$" # sync# echo 1 > /proc/sys/vm/drop_caches echo 2 > /proc/sys…

dotnet程序优化心得(三)

(4)继续优化――用空间换取时间 现在对每一个字符,都要用get_Item(object key)方法过一遍,可这个乖乖方法那么长,肯定太耗时间了,能不能用更简单的手段呢?改Hashtable?哇&#xff0c…

【Mininet】Mininet使用源码安装

实验参考: Mininet使用源码安装 实验步骤: 1. 更新软件(用#sudo apt-get update与#sudo apt-get upgrade)。 2. 从github上获取mininet源码(#git clone git://github.com/mininet/mininet)。 3. 获取完后&a…

【Mininet】Mininet可视化应用

实验参考: Mininet可视化应用 实验步骤: 1. 用命令启动mininet可视化界面(#cd mininet/mininet/example #./miniedit.py),同时开启另一终端打开Opendaylight。 2. 用鼠标选择左侧的对应的网络组件,然后在空…

【Mininet】Mininet命令延伸实验扩展

实验参考: Mininet命令延伸实验扩展 实验步骤: 1.用命令实现 #sudo mn --topo minimal #最小的网络拓扑,一个交换机下挂两个主机。 #sudo mn --topo linear,4 #每个交换机连接一个主机,交换机间相连接。本例:4个主机&a…

java非检查性异常有哪些_Java异常处理-检查性异常、非检查性异常、Error

一、Java异常处理详解异常.png目录:1.java中异常的分类1.1 异常(Exception)1.1.1 运行时异常(RuntimeException)可以不需要捕获1.1.2 编译异常(IOException)编译器会提示要捕获,如果不进行捕获则编译器会报错1.2 错误(Error)3.java处理异常机制4.throw和…

【Mininet】基于Mininet测量路径的损耗率

实验参考: 基于Mininet测量路径的损耗率 SDN常用控制器安装部署之POX篇 实验步骤: 1. 在装有mininet的虚拟机中新建文件mymininet.py并编辑以下内容,这里要注意一点,文中的dp0与dp1须填POX安装的虚拟机的地址,由于本次…

【Mininet】Mininet设置带宽之简单性能测试

实验参考: Mininet设置带宽之简单性能测试 实验步骤: 1. 进入mininet/custom目录下,通过vi mymininet1.py创建脚本并添加内容(本实验通过python脚本自定义拓扑,创建包含一个交换机、四个主机的网络拓扑)&am…

java 配置tocat_Tomcat安装配置及Eclipse配置详解

整个安装过程我们先学习安装jdk和配置然后是安装tomcat和配置,最后我们学习安装eclipse和配置以及web程序的使用和发布举例1. 安装jdk和配置(1)下载jdk安装包:(2)按照步骤点击下一步进行jdk软件的安装。(3)配置javajdk的环境变量**配置环境变量包括java_…

【Mininet】Mininet动态改变转发规则实验

实验参考: Mininet动态改变转发规则实验 SDN常用控制器安装部署之POX篇 实验步骤: 1. 在装有POX的虚拟机里,/root/pox目录下新建文件lab_controller.py,并编辑以下内容: 1 from pox.core import core2 3 import pox.o…

php搜索图片不显示不出来了,PHP CURL采集百度搜寻结果图片不显示问题的解决方法【第1/4页】...

1.根据关键字采集百度搜寻结果根据关键字采集百度搜寻结果&#xff0c;可以使用curl实现&#xff0c;代码如下&#xff1a;<?php function doCurl($url, $dataarray(), $headerarray(), $timeout30){$ch curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch…

数据库,XML,MDB --- 我们来TXT...

数据库,XML,MDB --- 我们来TXT... 转贴请注明来自http://blog.csdn.net/a11s 作者:董含君 blog已经迁移到http://a11s.cnblogs.com呵呵,有数据库当然用数据库,SQL Server多好用, mySQL多好用... 不能给客户端随便装服务啊,那就access或者其他单机的xsl之类,或者干脆XML XML是…

php文件怎么设置隐藏显示代码,php文件隐藏的方法

php文件隐藏的方法&#xff1a;1、在“httpd.conf”里任意位置添加代码为“AddType application/x-httpd-php .asp .py .pl .jsp aspx”&#xff1b;2、对PHP使用未知扩展名。隐藏你的.php文件今天做PHP在线手册镜像的时候看到了这个方法,哈哈,以前都没有注意到,所以说,手册是最…

【Mininet】Mininet脚本实现控制交换机行为

实验参考&#xff1a; Mininet脚本实现控制交换机行为 实验步骤&#xff1a; 1. 一台交换机两台主机&#xff0c;实现从1端口进入的数据流转发到2端口&#xff0c;从2端口进入的数据流转发到1端口。 1. 创建新文件mymininet1.py并编辑以下内容&#xff08;注意要将控制器设置为…

matlab2018b中svm无法运行,关于matlab2018a版本错误使用 svmclassify 分类器

当我们照常使用分类器函数svmclassify时&#xff0c;2018版的matlab会报出以下错误&#xff1a;解决办法&#xff1a;1&#xff0c;下载libsvm(一般下载最新版本就ok了)包&#xff0c;并将其添加至matlab的toolbox文件里。并打开matlab编辑器&#xff0c;主页 / 设置路径 / 添…

【Mininet】Mininet MAC地址学习实验

实验参考&#xff1a; Mininet MAC地址学习实验 实验步骤&#xff1a; 1. 在虚拟机上启动mininet&#xff0c;创建一个线型拓扑&#xff08;如下图所示&#xff09;&#xff0c;控制器设置为无&#xff08;# sudo mn –-topo linear –-mac –-switch ovsk –-controllernone&a…

【Mininet】基于Mininet的VxLAN实验

实验参考&#xff1a; 基于Mininet的VxLAN实验 实验步骤&#xff1a; 1. 如下图所示&#xff0c;在两台虚拟机中利用mininet创建两个网络&#xff0c;利用VxLAN连通这两个mininet环境。关闭默认的控制器后&#xff0c;通过下发流表确保网络的连通性&#xff1a; 2. 先查看两台虚…

Ajax基石脚本异步并发调用参数传递

在Ajax开发框架中&#xff0c;最基本的划分是服务器端和客户端。服务器端相对来说比较简单&#xff0c;只要是可以开发动态网页的语言都可以胜任&#xff1b;客户端浏览器就是JScript/JavaScript的天下了&#xff0c;好像没有看到有VBScript做的Ajax客户端库&#xff0c;就算它…