大话设计模式笔记之组合模式

来源:互联网 发布:网络印刷平台 编辑:程序博客网 时间:2024/06/06 00:28

一.定义

组合模式将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对当个对象的使用和多个对象的使用保持了一致性,屏蔽了客户端在使用时的差异,为客户端提供统一的操作接口,从而降低客户代码与被调用对象的耦合关系,方便系统的维护与扩展。

二.结构图

组合模式的结构图如(2-1)所示:

(2-1)

Client:客户端;

Component:组合模式中的对象接口声明,接口或者类中定义了子类公有方法,在适当的情况下,可以在父类中实现所有子类共有的默认行为;

Leaf:组合模式中表示单个对象,好比树型结构中的叶子节点,不包含任何的子节点;

Composite:组合对象,相当于树型结构中的枝节点可以有单个对象和组合对象,相比单个对象组合对象中会有一些操作组合对象的Add、Remove方法,管理多个对象。

三.代码实现

简单的组合模式可以通过定义一个公用的接口或者父类,让组合对象和单个对象都去实现这个接口。如果客户端传入的是单个对象则调用处理单个对象的方法,如果是组合对象,递归遍历组合对象,依次调用单个对象的方法。单个对象相当于树型结构中的叶子节点,它不包含任何子对象。组合对象相当于树型结构中的枝节点,可以包含更小的枝节点和叶子节点。

Java代码实现如下所示:

Component公共抽象类

package cn.lzz.componentpattern;/** * 公共的抽象组件 * @author Administrator * */public abstract class Component {protected String name;private static final String separator="- ";public Component(){}public Component(String name){this.name=name;}/** * @param component */public abstract void add(Component component);/** * @param component */public abstract void remove(Component component);/** * @param depth */public abstract void display(int depth);/** * 获取分隔符 * @param times * @return */protected String getSeparator(int times){StringBuilder sb=new StringBuilder();for(int i=0;i<times;i++){sb.append(Component.separator);}return sb.toString();}}

Leaf叶子节点

package cn.lzz.componentpattern;public class Leaf extends Component {public Leaf(String name){super(name);}@Overridepublic void add(Component component) {// TODO Auto-generated method stub}@Overridepublic void display(int depth) {// TODO Auto-generated method stubSystem.out.println(this.getSeparator(depth)+this.name);}@Overridepublic void remove(Component component) {// TODO Auto-generated method stub}}

Composite枝节点

package cn.lzz.componentpattern;import java.util.LinkedList;import java.util.List;public class Composite extends Component {private List<Component> children=new LinkedList<Component>();public Composite(String name){super(name);}@Overridepublic void add(Component component) {// TODO Auto-generated method stubthis.children.add(component);}@Overridepublic void display(int depth) {// TODO Auto-generated method stubSystem.out.println(this.getSeparator(depth)+name);for(Component component:children){//同一层的分隔符数量相同component.display(depth+2);}}@Overridepublic void remove(Component component) {// TODO Auto-generated method stubthis.children.remove(component);}}

ComponentTest测试代码

package cn.lzz.componentpattern;public class ComponentTest {public static void main(String[] args) {ComponentTest componentTest=new ComponentTest();//根节点Component root=componentTest.getComposite("root");//叶子节点Component leafA=componentTest.getLeaf("leafA");Component leafB=componentTest.getLeaf("leafB");root.add(leafA);root.add(leafB);//分支Component compositeX=componentTest.getComposite("compositeX");//分支中的叶子节点Leaf leafXA=componentTest.getLeaf("leafXA");Leaf leafXB=componentTest.getLeaf("leafXB");compositeX.add(leafXA);compositeX.add(leafXB);root.add(compositeX);//叶子节点Leaf leafC=componentTest.getLeaf("leafC");Leaf leafD=componentTest.getLeaf("leafD");root.add(leafC);root.add(leafD);root.remove(leafD);root.display(1);}private  Leaf getLeaf(String name){return new Leaf(name);}private  Composite getComposite(String name){return new Composite(name);}}

执行结果如下所示:

- root- - - leafA- - - leafB- - - compositeX- - - - - leafXA- - - - - leafXB- - - leafC

四.组合模式的两种实现方式

透明方式:在Component中声明所有用来管理子对象的方法中,其中包括add、remove等。这样Component的所有子类中都有add、remove方法。这样做的好处是叶节点和枝节点对于外界来说没有区别,它们具有完全一致的行为接口。但这样也有一个问题,叶子节点本来不应该有add和remove方法,实现了这两个方法也没有意义。

安全方式:Component中不去声明add、remove方法,只在composite中声明,这样叶子节点就不用去实现这两个没有意义的方法。这样一来叶子节点和枝节点就有了不同的接口,在使用的时候就需要去判断。

五.适用场景

当需求需要体现部分与整体层次结构时,以及客户端可以忽略单个对象和组合对象时,统一使用组合结构中的对象时,可以考虑使用组合模式。



0 0
原创粉丝点击