网站搭建定制,网站开发就业,网络技术服务,服务注册中心有哪些什么是组合模式
组合模式(Composite Pattern)#xff1a;组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象#xff08;即叶子对象#xff09;和组合对象#xff08;即容器对象#xff09;的使用具有一致性#xff0c;组合模式又可以…什么是组合模式
组合模式(Composite Pattern)组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象即叶子对象和组合对象即容器对象的使用具有一致性组合模式又可以称为“整体—部分”(Part-Whole)模式它是一种对象结构型模式。
组合模式将对象组织到树结构中可以用来描述整体与部分的关系可以使客户端将单纯元素与复合元素同等看待。
树结构在过程性的编程语言中曾经发挥了巨大的作用在面向对象的语言中树结构也同样威力巨大。一个基于继承的类型的等级结构便是一个树结构一个基于组合的对象结构也是一个树结构。
在树形结构中最顶层的节点被称为根节点根节点下面可以包含树枝节点和叶子节点树枝节点下面又可以包含树枝节点和叶子节点如下图所示 由上图可以看出其实根节点和树枝节点本质上属于同一种数据类型可以作为容器使用而叶子节点与树枝节点在语义上不属于用一种类型。但是在组合模式中会把树枝节点和叶子节点看作属于同一种数据类型用统一接口定义让它们具备一致行为。
这样在组合模式中整个树形结构中的对象都属于同一种类型带来的好处就是用户不需要辨别是树枝节点还是叶子节点可以直接进行操作给用户的使用带来极大的便利。
模式的结构
组合模式UML类图 UML类图讲解 Component抽象构件它可以是接口或抽象类为叶子构件和容器构件对象声明接口在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法如增加子构件、删除子构件、获取子构件等。 Leaf叶子构件它在组合结构中表示叶子节点对象叶子节点没有子节点它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法可以通过异常等方式进行处理。 Composite容器构件它在组合结构中表示容器节点对象容器节点包含子节点其子节点可以是叶子节点也可以是容器节点它提供一个集合用于存储子节点实现了在抽象构件中定义的行为包括那些访问及管理子构件的方法在其业务方法中可以递归调用其子节点的业务方法。 优点和缺点
优点
组合模式的主要优点如下 组合模式可以清楚地定义分层次的复杂对象表示对象的全部或部分层次它让客户端忽略了层次的差异方便对整个层次结构进行控制。 客户端可以一致地使用一个组合结构或其中单个对象不必关心处理的是单个对象还是整个组合结构简化了客户端代码。 在组合模式中增加新的容器构件和叶子构件都很方便无须对现有类库进行任何修改符合“开闭原则”。 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案通过叶子对象和容器对象的递归组合可以形成复杂的树形结构但对树形结构的控制却非常简单。 缺点
组合模式的主要缺点如下 破坏了“单一职责原则”。 在增加新构件时很难对容器中的构件类型进行限制。有时候我们希望一个容器中只能有某些特定类型的对象例如在某个文件夹中只能包含文本文件使用组合模式时不能依赖类型系统来施加这些约束因为它们都来自于相同的抽象层在这种情况下必须通过在运行时进行类型检查来实现这个实现过程较为复杂。 组合模式的实现根据所实现接口的区别分为透明式组合模式和安全式组合模式。
透明式
作为第一种选择在Component里面声明所有的用来管理子类对象的方法包括add()、remove()以及 getChild()方法。这样做的好处是所有的构件类都有相同的接口。在客户端看来树叶类对象与合成类对象的区别起码在接口层次上消失了客户端可以同等地对待所有的对象。这就是透明形式的合成模式。
这个选择的缺点是不够安全因为树叶类对象和合成类对象在本质上是有区别的。树叶类对象不可能有下一个层次的对象因此add()、remove()以及 getChild()方法没有意义但是在编译时期不会出错而只会在运行时期才会出错。
透明式的组合模式要求所有的具体构件类不论树枝构件还是树叶构件都符合一个固定的接口类图如下 透明式组合模式涉及到抽象构件角色、树叶构件角色、树枝构件角色三种模式 抽象构件(Component角色这是一个抽象角色它给参加组合的对象规定一个接口规范共有的接口及默认行为。这个接口可以用来管理所有的子对象要提供一个接口以规范取得和管理下层组件的接口包括 add()、remove()以及getChild()之类的方法。树叶构件(Leaf〉角色:代表参加组合的树叶对象定义出参加组合的原始对象的行为。树叶类会给出add()、remove()以及getChild()之类的用来管理子类对象的方法的平庸实现。树枝构件(Composite角色:代表参加组合的有子对象的对象定义出这样的对象的行为。 我们都见过画图软件一个绘图系统给出各种工具用来描绘线、长方形和原形等基本图形组成的图形。一个复杂的图形肯定是有这些基本的图形组成的。本模式我们就以这为例子来讲解。
由于一个复杂的图形是由基本图形组合而成的因此一个组合的图形应当有一个列表存储对所有的基本图形对象的引用。复合图形的draw()方法在调用时应当逐一调用所有列表上的基本图形对象的draw()方法。
透明形式的组合模式意味着不仅只有树枝构件角色才配备有管理聚集的方法树叶构件也有这些方法虽然树叶构件的这些方法是平庸的。透明式的组合模式的类图如下 抽象构件角色 树枝构件角色
public class Picture extends Graphics {private Vector items new Vector(10);//具体管理方法增加一个子构件对象public void add(Graphics graphics){items.add(graphics);}//删除一个子构件对象public void remove(Graphics graphics){items.remove(graphics);}//返回一个子构件对象public .Graphics getChild(int i){return (Graphics) items.get(i);}Overridepublic void draw() {for (int i 0; i items.size(); i) {Graphics graphics (Graphics) items.get(i);graphics.draw();}}
}树叶构件角色
package com.zeus;public class Line extends Graphics{Overridevoid draw() {System.out.println(画了一条线);}Overridevoid add() {}Overridevoid remove() {}OverrideGraphics getChild(int i) {return null;}
}package com.zeus;public class Circle extends Graphics{Overridevoid draw() {System.out.println(画了一个圆形);}Overridevoid add() {}Overridevoid remove() {}OverrideGraphics getChild(int i) {return null;}
}
package com.zeus;public class Rectangle extends Graphics{Overridevoid draw() {System.out.println(画了一个长方形);}Overridevoid add() {}Overridevoid remove() {}OverrideGraphics getChild(int i) {return null;}
}测试 打印的结果 画了一个长方形 画了一条线 画了一个长方形 安全式
第二种选择是在 Composite类里面声明所有的用来管理子类对象的方法。这样的做法是安全的做法因为树叶类型的对象根本就没有管理子类对象的方法因此如果客户端对树叶类对象使用这些方法时程序会在编译时期出错。编译通不过就不会出现运行时期错误。
这个选择的缺点是不够透明因为树叶类和合成类将具有不同的接口。
安全式的组合模式要求管理具体的方法只出现在树枝构件类中如下图所示 安全式组合模式涉及到抽象构件角色、树叶构件角色、树枝构件角色这三个角色 抽象构件角色Component这是一个抽象角色他给参加组合的对象定义出公共的接口及其默认行为可以用来管理所有的子对象。组合对象通常把它所包含的子对象当作类型为component的对象在安全式的组合模式里构件角色并不定义出管理子对象的方法树叶构件角色Leaf树叶对象是没有下级子对象的对象定义出参加组合的原始对象的行为树枝构件角色Composite代表参加组合的有下级子对象的对象树枝构件类给出所有的管理子对象的方法如add()remove()以及getChild()等方法 同样以上面的绘图系统为例子讲解安全式组合模式。安全式组合模式意味着只有树枝构件角色才能配备有管理聚集的方法而树叶构件角色则没有这些方法。UML类图如下 抽象构件角色 树枝构件角色
public class Picture extends Graphics{private Vector items new Vector(10);//具体管理方法增加一个子构件对象public void add(Graphics graphics){items.add(graphics);}//删除一个子构件对象public void remove(Graphics graphics){items.remove(graphics);}//返回一个子构件对象public Graphics getChild(int i){return (Graphics) items.get(i);}Overridepublic void draw() {for (int i 0; i items.size(); i) {Graphics graphics (Graphics) items.get(i);graphics.draw();}}
}树叶构件角色 测试 打印结果 画了一个长方形。。。。 画了一条线。。。。 画了一个长方形。。。。 适用环境
在以下情况下可以考虑使用组合模式 在具有整体和部分的层次结构中希望通过一种方式忽略整体与部分的差异客户端可以一致地对待它们。 在一个使用面向对象语言开发的系统中需要处理一个树形结构。 在一个系统中能够分离出叶子对象和容器对象而且它们的类型不固定需要增加一些新的类型。