免费推广自己的网站,远程wordpress数据库,建设网站挂广告赚钱,开个人网站需要多少钱生活中存在很多 “部分-整体” 的关系#xff0c;例如#xff1a;大学中的学校与学院、学院与专业的关系。高楼与楼层和房间之间的关系等等。在软件开发中也有类似的情况。这些简单对象与复合对象之间的关系#xff0c;如果用组合模式#xff08;把学校、院、系都看作是组织…生活中存在很多 “部分-整体” 的关系例如大学中的学校与学院、学院与专业的关系。高楼与楼层和房间之间的关系等等。在软件开发中也有类似的情况。这些简单对象与复合对象之间的关系如果用组合模式把学校、院、系都看作是组织结构他们之间没有继承的关系而是一种树形结构可以更好的实现管理操作来实现会很方便。
一、基本介绍
1、组合模式Composite Pattern又叫部分整体模式它创建了对象组的树形结构将对象组合成树状结构以表示“整体-部分”的层次关系。 2、组合模式依据树形结构来组合对象用来表示部分以及整体层次。 3、这种设计模式属于结构型模式。 4、组合模式使得用户对单个对象和组合对象的访问具有一致性即组合能让客户以一致的方式处理个别对象以及组合对象。 5、优点组合模式使得客户端代码可以一致地处理单个对象和组合对象无需关系自己处理的是单个对象还是组合对象这简化了客户端代码更容易在组合体内加入新的对象客户端不会因为加入了新的对象而更改源代码满足 “开闭原则 OCP”。 6、缺点设计复杂客户端需要花更多时间理清类之间的层次关系。不容易限制容器中构建不容易用继承的方式增加构建的新功能。
二、组合模式——结构类图
组合模式分为透明式的组合模式和安全式组合模式 1、透明方式在该方法中由于抽象构建声明了所有子类中的全部方法所以客户端无需区别树叶对象和树枝对象。对客户端来说是透明的。其缺点是树叶构件本来没有 Add()、Remove() 及 GetChild() 方法却要实现它们空实现或抛异常这样会带来一些安全性问题。 2、安全方式在该方式中将管理子构件的方法移到树枝构件中抽象构件和树叶构件没有对子对象的管理方法这样就避免了上一种方式的安全性问题但由于叶子和分支有不同的接口客户端在调用时要知道树叶对象和树枝对象的存在所以失去了透明性。 三、组合模式代码案例分析
【1】抽象构件Component角色 主要作用是为树叶和树枝构件生命公共接口并实现他们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口add/remove)。在安全式的组合模式中不声明访问和管理子类的接口管理工作由树枝构建完成。
public abstract class AbstractComponent {//学校的名称private String name;//备注private String remark;//定义一个输入的抽象方法public abstract void output();//非叶子节点都具有的增加和删除方法public void add(AbstractComponent abstractComponent) {//当重写此方法直接调用时就会抛出此异常。与Arrays.asList()内部类中的add与remove写法一致throw new UnsupportedOperationException();}public void remove(AbstractComponent abstractComponent) {throw new UnsupportedOperationException();}//构造器public AbstractComponent(String name, String remark) {super();this.name name;this.remark remark;}//get/set方法 tostring方法 略}
}【2】树枝构件Composite角色 是组合中的分支节点对象它有子节点。它实现了抽象构件角色中声明的接口它的主要作用是
public class University extends AbstractComponent{//构造器public University(String name, String remark) {super(name, remark);}//大学中包含多个学院ListAbstractComponent college new ArrayListAbstractComponent();//重写输出方法:输出叶子节点Overridepublic void output() {System.out.println(super.getName());for (AbstractComponent abstractComponent : college) {abstractComponent.output();}}//组合类也就是树枝节点需要重写add与remove方法Overridepublic void add(AbstractComponent abstractComponent) {college.add(abstractComponent);}Overridepublic void remove(AbstractComponent abstractComponent) {college.remove(abstractComponent);}
}【3】学院类也是树枝构件Composite角色与上述基本一致。
public class College extends AbstractComponent{//构造器public College(String name, String remark) {super(name, remark);}ListAbstractComponent list new ArrayList();//输入Overridepublic void output() {for (AbstractComponent abstractComponent : list) {abstractComponent.output();}}//重写添加和删除方法Overridepublic void add(AbstractComponent abstractComponent) {list.add(abstractComponent);}Overridepublic void remove(AbstractComponent abstractComponent) {list.remove(abstractComponent);}
}【4】树叶构件Leaf角色 是组合中的叶节点对象它没有子节点用于实现抽象构件角色中 声明的公共接口。
public class Major extends AbstractComponent{//构造器public Major(String name, String remark) {super(name, remark);}//add , remove 就不用写了因为他是叶子节点//输入Overridepublic void output() {System.out.println(getName());}}【5】测试类
public class Client {public static void main(String[] args) {//定义一个大学AbstractComponent university new University(浙江大学, 浙江人的骄傲);//定义一个学院AbstractComponent college new College(计算机学院, 简称妓院);//将妓院添加至学校university.add(college);//定义一个专业AbstractComponent major new Major(计算机科学与技术, 考研大专业);//添加至学院college.add(major);//输出计算机科学与技术 输入的都是叶子节点的output方法major.output();college.output();university.output();}
}四、组合模式源码分析
【1】HashMap 组合模式首先定义了抽象构建角色 MapK,V
public interface MapK,V {....}【2】使用接口适配器模式定义了抽象实现AbstractMap
public abstract class AbstractMapK,V implements MapK,V {public V put(K key, V value) {//由子类实现throw new UnsupportedOperationException();}......
}【3】HashMap等实现类属于树枝构建角色组合了Node叶子节点类
public class HashMapK,V extends AbstractMapK,Vimplements MapK,V, Cloneable, Serializable {public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}public void putAll(Map? extends K, ? extends V m) {putMapEntries(m, true);}......final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {NodeK,V[] tab; NodeK,V p; int n, i;......}
}【4】Node 类是上述类的内部类也就是组合模式中的树叶构建数组存储时通过 put 方法存入 Node 对象中叶子节点 Node 中不包含添加方法等只包含一些属性和其 get/set 方法
public class HashMapK,V extends AbstractMapK,Vimplements MapK,V, Cloneable, Serializable {......static class NodeK,V implements Map.EntryK,V {final int hash;final K key;V value;NodeK,V next;Node(int hash, K key, V value, NodeK,V next) {this.hash hash;this.key key;this.value value;this.next next;}public final K getKey() { return key; }public final V getValue() { return value; }public final String toString() { return key value; }public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}public final V setValue(V newValue) {V oldValue value;value newValue;return oldValue;}public final boolean equals(Object o) {if (o this)return true;if (o instanceof Map.Entry) {Map.Entry?,? e (Map.Entry?,?)o;if (Objects.equals(key, e.getKey()) Objects.equals(value, e.getValue()))return true;}return false;}}......
}五、组合模式的注意事项和细节 ☛ 简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题。 ☛ 具有较强的扩展性。当我们要更改组合对象时我们只需要调整内部的层次关系客户端不用做任何改动。 ☛ 方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节,容器添加节点或者叶子。从而创建出复杂的树形结构。 ☛ 需要遍历组织机构或者处理的对象具有树形结构时非常适合使用组合模式。 ☛ 当要求较高的抽象性时如果节点和叶子有很多差异的话例如很多方法和属性都不一样不适合使用组合模式。