柳江区城乡住房建设局网站,营销广告策划方案,搬瓦工wordpress安装,企业建设官方网站作用及意义1、简介
1.1、概述
树形结构在软件中随处可见#xff0c;例如操作系统中的目录结构、应用软件中的菜单、办公系统中的公司组织结构等。如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题。组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形…1、简介
1.1、概述
树形结构在软件中随处可见例如操作系统中的目录结构、应用软件中的菜单、办公系统中的公司组织结构等。如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题。组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形结构或者树形结构的一部分也可以一致性地处理树形结构中的叶子节点不包含子节点的节点和容器节点包含子节点的节点。
对于树形结构当容器对象例如文件夹的某一个方法被调用时将遍历整个树形结构寻找也包含这个方法的成员对象可以是容器对象也可以是叶子对象并调用执行牵一而动百其中使用了递归调用的机制来对整个结构进行处理。由于容器对象和叶子对象在功能上的区别在使用这些对象的代码中必须有区别地对待容器对象和叶子对象而实际上大多数情况下希望一致地处理它们因为对于这些对象的区别对待将会使得程序非常复杂。组合模式为解决此类问题而诞生它可以让叶子对象和容器对象的使用具有一致性。
1.2、定义
组合多个对象形成树形结构以表示具有“部分—整体”关系的层次结构。组合模式对单个对象即叶子对象和组合对象即容器对象的使用具有一致性又可以称为“部分—整体”Part-Whole模式它是一种对象结构型模式。
2、解析
在组合模式中引入了抽象构件类Component它是所有容器类和叶子类的公共父类客户端针对Component进行编程。
2.1、UML类图 可以看出在组合模式结构图中包含以下3个角色
Component抽象构件它可以是接口或抽象类为叶子构件和容器构件对象声明接口在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法例如增加子构件、删除子构件、获取子构件等。Leaf叶子构件它在组合模式结构中表示叶子节点对象。叶子节点没有子节点它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法可以通过捕获异常等方式进行处理。Composite容器构件它在组合模式结构中表示容器节点对象。容器节点包含子节点其子节点可以是叶子节点也可以是容器节点。它提供一个集合用于存储子节点实现了在抽象构件中定义的行为包括那些访问及管理子构件的方法在其业务方法中可以递归调用其子节点的业务方法。
组合模式的关键是定义了一个抽象构件类它既可以代表叶子又可以代表容器。客户端针对该抽象构件类进行编程无须知道它到底表示的是叶子还是容器可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系在容器对象中既可以包含叶子也可以包含容器以此实现递归组合形成一个树形结构。
如果不使用组合模式客户端代码将过多地依赖于容器对象复杂的内部实现结构。容器对象内部实现结构的变化将引起客户代码的频繁变化从而带来了代码维护复杂、可扩展性差等弊端。组合模式的引入将在一定程度上解决这些问题。
2.2、代码示例
对于组合模式中的抽象构件角色其典型代码如下
abstract class Component {// 添加成员public abstract void add(Component component);// 删除成员public abstract void remove(Component component);// 获取成员public abstract Component getChild(int i);// 业务方法public abstract void operation();
}一般将抽象构件类设计为接口或抽象类将所有子类共有方法的声明和实现放在抽象构件类中。对于客户端而言将针对抽象构件编程而无须关心其具体子类是容器构件还是叶子构件。
如果继承抽象构件的是叶子构件则其典型代码如下
public class Leaf extends Component{Overridepublic void add(Component component) {// 异常处理或错误提示}Overridepublic void remove(Component component) {// 异常处理或错误提示}Overridepublic Component getChild(int i) {// 异常处理或错误提示return null;}Overridepublic void operation() {// 叶子构件具体业务方法的实现}
}作为抽象构件类的子类在叶子构件中需要实现在抽象构件类中声明的所有方法包括业务方法以及管理和访问子构件的方法。由于叶子构件不能再包含子构件因此在叶子构件中实现子构件管理和访问方法时需要提供异常处理或错误提示。当然这无疑会给叶子构件的实现带来麻烦。
如果继承抽象构件的是容器构件则其典型代码如下
public class Composite extends Component{private ArrayListComponent list new ArrayList();Overridepublic void add(Component component) {list.add(component);}Overridepublic void remove(Component component) {list.remove(component);}Overridepublic Component getChild(int i) {return list.get(i);}Overridepublic void operation() {// 容器构件具体业务方法的实现// 递归调用成员构件的业务方法for(Component component:list){component.operation();}}
}在容器构件中实现了在抽象构件中声明的所有方法既包括业务方法也包括用于访问和管理成员子构件的方法例如add、remove和getChild等方法。需要注意的是在实现具体业务方法时由于容器构件充当的是容器角色包含成员构件因此它将调用其成员构件的业务方法。在组合模式结构中由于容器构件中仍然可以包含容器构件因此在对容器构件进行处理时需要使用递归算法即在容器构件的operation方法中递归调用其成员构件的operation方法。
3、透明组合模式与安全组合模式
3.1、透明组合模式
透明组合模式中抽象构件Component中声明了所有用于管理成员对象的方法包括add、remove以及getChild等方法这样做的好处是确保所有的构件类都有相同的接口。在客户端看来叶子对象与容器对象所提供的方法是一致的客户端可以相同地对待所有的对象。透明组合模式也是组合模式的标准形式其完整结构如图所示 透明组合模式的缺点是不够安全因为叶子对象和容器对象在本质上是有区别的。叶子对象不可能有下一个层次的对象即不可能包含成员对象因此为其提供add、remove以及getChild等方法是没有意义的这在编译阶段不会出错但在运行阶段如果调用这些方法可能会出错如果没有提供相应的错误处理代码。
3.2、安全组合模式
安全组合模式中在抽象构件Component中没有声明任何用于管理成员对象的方法而是在Composite类中声明并实现这些方法。这种做法是安全的因为根本不向叶子对象提供这些管理成员对象的方法对于叶子对象客户端不可能调用到这些方法。安全组合模式的结构如图所示 安全组合模式的缺点是不够透明。因为叶子构件和容器构件具有不同的方法且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义因此客户端不能完全针对抽象编程必须有区别地对待叶子构件和容器构件。在实际应用中安全组合模式的使用频率也非常高在Java AWT中使用的组合模式就是安全组合模式。
4、总结
组合模式使用面向对象的思想来实现树形结构的构建与处理描述了如何将容器对象和叶子对象进行递归组合实现简单灵活性好。由于在软件开发中存在大量的树形结构因此组合模式是一种使用频率较高的结构型设计模式。Java SE中的AWT和Swing包的设计就基于组合模式在这些界面包中为用户提供了大量的容器构件例如Container和成员构件例如Checkbox、Button和TextComponent等其结构如图所示 Component类是抽象构件Checkbox、Button和TextComponent是叶子构件而Container是容器构件。在AWT中包含的叶子构件还有很多因为篇幅限制没有在图中一一列出。在一个容器构件中可以包含叶子构件也可以继续包含容器构件这些叶子构件和容器构件一起组成了复杂的GUIGraphical User Interface图形用户界面。
除此以外在XML解析、组织结构树处理、文件系统设计等领域组合模式都得到了广泛应用。
4.1、主要优点
组合模式可以清楚地定义分层次的复杂对象表示对象的全部或部分层次。它让客户端忽略了层次的差异方便对整个层次结构进行控制。客户端可以一致地使用一个组合结构或其中单个对象不必关心处理的是单个对象还是整个组合结构简化了客户端代码。在组合模式中增加新的容器构件和叶子构件都很方便无须对现有类库进行任何修改符合开闭原则。组合模式为树形结构的面向对象实现提供了一种灵活的解决方案。通过叶子对象和容器对象的递归组合可以形成复杂的树形结构但对树形结构的控制却非常简单。
4.2、主要缺点
在增加新构件时很难对容器中的构件类型进行限制。有时希望一个容器中只能有某些特定类型的对象例如在某个文件夹中只能包含文本文件。使用组合模式时不能依赖类型系统来施加这些约束因为它们都来自相同的抽象层。在这种情况下必须通过在运行时进行类型检查来实现这个实现过程较为复杂。
4.3、适用场景
1在具有整体和部分的层次结构中希望通过一种方式忽略整体与部分的差异客户端可以一致性地对待它们。
2在一个使用面向对象语言开发的系统中需要处理一个树形结构。
3在一个系统中能够分离出叶子对象和容器对象而且它们的类型不固定将来需要增加一些新的类型。