组合模式——针对于“部分-整体”层次结构的设计模式

一、组合模式的定义

        组合模式又称合成模式,是用来描述部分与整体关系的一种设计模式。它的定义是:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

        组合模式中的几个角色:

(1)Component抽象构件
         定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性。
(2)Leaf叶子构件
         叶子对象,其下再也没有其他的分支,也就是遍历的最小单位。
(3)Composite树枝构件
         树枝对象,它的作用是组合树枝节点和叶子节点形成一个树形结构。
        

二、组合模式的通用代码

抽象构件


public abstract class Component {
     
    //个体和整体都具有的共享
     
    public void doSomething() {
             
        //编写业务逻辑
     
    }

}

树枝构件


public class Composite extends Component {
     
    //构件容器
     
    private ArrayList<Component> componentArrayList = new ArrayList<Component>();
     
    //增加一个叶子构件或树枝构件
     
    public void add(Component component) {
                     
        this.componentArrayList.add(component);
     
    }
     
    //删除一个叶子构件或树枝构件
     
    public void remove(Component component) {
                 
        this.componentArrayList.remove(component);
     
    }
     
    //获得分支下的所有叶子构件和树枝构件
     
    public ArrayList<Component> getChildren() {
             
        return this.componentArrayList;
     
    }

}

叶子构件


public class Leaf extends Component {

     /*
      
      * 可以重写父类方法
      
      * public void doSomething() {
      
      *
      
      * }
      
      */

}

场景类


public class Client {
     
    public static void main(String[] args) {
            
        //创建一个根节点
             
        Composite root = new Composite();
             
        root.doSomething();
             
        //创建一个树枝构件
             
        Composite branch = new Composite();
             
        //创建一个叶子节点
             
        Leaf leaf = new Leaf();
             
        //建立整体
             
        root.add(branch);
             
        branch.add(leaf);
     
    }
     
    //通过递归遍历树
     
    public static void display(Composite root) {
             
        for(Component c:root.getChildren()){
                  
            if(c instanceof Leaf) { //叶子节点
                          
                c.doSomething();
                  
            } else { //树枝节点
                          
                display((Composite)c);
                  
            }
             
        }
     
    }

}

三、组合模式的应用

组合模式的优点:

  • 高层模块调用简单

        一棵树形机构中的所有节点都是Component,局部和整体对调用者来说没有任何区别。也就是说,高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。

  • 节点自由增加

        如果想增加一个树枝节点、树叶节点是不是都很容易,只要找到它的父节点就行了。非常容易扩展,符合开闭原则,对以后的维护非常有利。

组合模式的缺点:

        直接使用了实现类,与依赖倒转原则冲突。

组合模式的使用场景:

  • 维护和展示部分-整体关系的场景,如树形菜单、文件和文件夹管理。
  • 从一个整体中能够独立出部分模块或功能的场景。

组合模式的注意事项:

        只要是树形结构,就要考虑使用组合模式。

四、组合模式的扩展

1. 组合模式的不同实现

        组合模式有两种不同的实现:透明模式安全模式

  • 安全模式

        它是把树枝节点和树叶节点彻底分开,树枝节点单独拥有用来组合的方法。这种方法比较安全,我们通常使用的就是这种模式。

  • 透明模式

        它是把组合使用的方法放在抽象类中,不管叶子对象还是树枝对象都有相同的结构。通过判断是getChildren的返回值确定是叶子节点还是树枝节点。

        这种模式如果处理不当,会在运行期出现问题。因此不建议使用这种方式。

        

抽象构件 


public abstract class Component {
     
    //个体和整体都具有的共享
     
    public void doSomething(){
             
        //编写业务逻辑
     
    }
     
    //增加一个叶子构件或树枝构件
     
    public abstract void add(Component component);
     
    //删除一个叶子构件或树枝构件
     
    public abstract void remove(Component component);
     
    //获得分支下的所有叶子构件和树枝构件
     
    public abstract ArrayList<Component> getChildren();

}

叶子构件 


public class Leaf extends Component {
     
    @Deprecated
     
    public void add(Component component) throws UnsupportedOperationException {

        //空实现,直接抛弃一个"不支持请求"异常
             
        throw new UnsupportedOperationException();
     
    }
     
    @Deprecated
     
    public void remove(Component component)throws UnsupportedOperationException {

        //空实现
             
        throw new UnsupportedOperationException();
     
    }
     
    @Deprecated
     
    public ArrayList<Component> getChildren()throws UnsupportedOperationException {

        //空实现
             
        throw new UnsupportedOperationException();
     
    }

}

        加Deprecated注解的作用:在编译器期告诉调用者,该方法已经失效,可能会出现错误,在运行期也会抛出UnsupportedOperationException的异常。

        在透明模式下,遍历树形结构比较容易,不用进行强制类型转换。


public class Client {
     
    //通过递归遍历树
     
    public static void display(Component root) {
             
        for(Component c:root.getChildren()) {
                  
            if(c instanceof Leaf) { //叶子节点
                          
                c.doSomething();
                  
            } else { //树枝节点
                          
                display(c);
                  
            }
          
        }
     
    }

}

        当然,透明模式也具有一定的好处,它遵循了依赖倒转原则,方便系统进行扩展。

2. 组合模式的遍历

        可以增加一个父结点,从而可实现树结构的前序遍历、中序遍历和后序遍历。

发布了67 篇原创文章 · 获赞 69 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_34519487/article/details/104254991