java设计模式--组合模式

Posted rhodesis

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java设计模式--组合模式相关的知识,希望对你有一定的参考价值。

组合模式

  组合模式主要是用来将对象合成树型结构以表示“整体-部分”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。

组合模式的适用性

  • 想通过组合模式表示对象的部分-整体层次结构。

  • 希望用户能够忽略组合对象和单个对象的不同,用户将统一的使用组合结构中的所有对象。

 

组合模式根据所实现的接口的区别一共有两种方式实现:安全式和透明式。我们来分别学习一下两种实现方式的不同

安全式组合模式的结构图

技术图片

 

安全式组合模式一共有如下三类角色构成:

  1. 抽象构件角色(Component):它为组合中的对象声明接口,给出参加组合对象组件的共有的抽象方法。

  2. 树叶构件角色(Leaf):它在组合模式中表示叶节点,叶节点没有子节点。

  3. 树枝构件角色(Composite):它定义了有子部件的组件的行为,同时定义了管理其子部件的方法,例如:AddChild(),RemoveChild()方法。

接下来通过代码来实现安全式组合模式:

  首先定义一个根的接口

public interface Component 
    public void print(String preStr);

  其次定义树枝组件

public class Composite implements Component 
    private String name;
    private List<Component> chileComponents = new ArrayList<Component>();

    public Composite(String name) 
        this.name = name;
    

    public void AddChild(Component child) 
        chileComponents.add(child);
    

    public void RemoveChild(Component child) 
        chileComponents.remove(child);
    

    public List<Component> GetChild() 
        return chileComponents;
    

    @Override
    public void print(String preStr) 
        System.out.println(preStr + "-" + name);
        if (chileComponents.size() > 0) 
            preStr += " ";
            for (Component c : chileComponents) 
                c.print(preStr);
            
        
    

  定义树叶组件

public class Leaf implements Component 
    private String name;

    public Leaf(String name) 
        this.name = name;
    

    @Override
    public void print(String preStr) 
        System.out.println(preStr + "-" + name);
    

   通过客户端来测试该组合模式

public class Client 
    public static void main(String[] args) 
        Composite root = new Composite("中西药");
        Composite c1 = new Composite("中药");
        Composite c2 = new Composite("西药");

        Leaf leaf1 = new Leaf("人参");
        Leaf leaf2 = new Leaf("田七");
        Leaf leaf3 = new Leaf("阿莫西林");
        Leaf leaf4 = new Leaf("葡萄糖");
        root.AddChild(c1);
        root.AddChild(c2);
        c1.AddChild(leaf1);
        c1.AddChild(leaf2);
        c2.AddChild(leaf3);
        c2.AddChild(leaf4);
        root.print("");
    


输出结果如下:
   -中西药
    -中药
     -人参
     -田七
    -西药
     -阿莫西林
     -葡萄糖
public class Client 
    public static void main(String[] args) 
        Composite root = new Composite("中西药");
        Composite c1 = new Composite("中药");
        Composite c2 = new Composite("西药");

        Leaf leaf1 = new Leaf("人参");
        Leaf leaf2 = new Leaf("田七");
        Leaf leaf3 = new Leaf("阿莫西林");
        Leaf leaf4 = new Leaf("葡萄糖");
        root.AddChild(c1);
        root.AddChild(c2);
        c1.AddChild(leaf1);
        c1.AddChild(leaf2);
        c2.AddChild(leaf3);
        c2.AddChild(leaf4);
        root.print("");
    


输出结果如下:
   -中西药
    -中药
     -人参
     -田七
    -西药
     -阿莫西林
     -葡萄糖

  由上述实现可以看出,树枝构件类给出了GetChild()、AddChild()、RemoveChild()等方法的声明和实现而树叶构件类则没有实现这些方法,因为树叶构件类没有子类所以完全不需要实现这些方法,这样的做法是安全的,但是这种方式不够透明,树枝构件类和树叶构件类分别来自不同的接口。透明的方式是把树枝和树叶构件类都实现相同的接口,这样有一个问题就是需要注意树叶构件类不会实现类似于GetChild()、AddChild()、RemoveChild()这些方法。

透明式组合模式的结构图

技术图片

 

  与安全式组合模式不同,透明式组合模式要求所有的构件类,不论是树枝构件类还是树叶构件类都实现于一个固定的接口,下面将安全式结构模式改写一下来实现透明式组合模式的实现:

  根的接口如下:

public abstract class Component 
    public abstract void print(String preStr);

    public void AddChild(Component child) 
        throw new UnsupportedOperationException("该对象不支持此方法");
    

    public void RemoveChild(Component child) 
        throw new UnsupportedOperationException("该对象不支持此方法");
    

    public List<Component> GetChild() 
        throw new UnsupportedOperationException("该对象不支持此方法");
    

  树枝构件类:

public class Composite extends Component 
    private String name;
    private List<Component> chileComponents = new ArrayList<Component>();

    public Composite(String name) 
        this.name = name;
    

    @Override
    public void AddChild(Component child) 
        chileComponents.add(child);
    

    @Override
    public void RemoveChild(Component child) 
        chileComponents.remove(child);
    

    @Override
    public List<Component> GetChild() 
        return chileComponents;
    

    @Override
    public void print(String preStr) 
        System.out.println(preStr + "-" + name);
        if (chileComponents.size() > 0) 
            preStr += " ";
            for (Component c : chileComponents) 
                c.print(preStr);
            
        
    
    

  树叶构件类还是和之前一样不用重写GetChild()、AddChild()、RemoveChild()方法:

public class Leaf extends Component 
    private String name;

    public Leaf(String name) 
        this.name = name;
    

    @Override
    public void print(String preStr) 
        System.out.println(preStr + "-" + name);
    

  客户端:

public class Client 
    public static void main(String[] args) 
        Component root = new Composite("中西药");
        Component c1 = new Composite("中药");
        Component c2 = new Composite("西药");

        Component leaf1 = new Leaf("人参");
        Component leaf2 = new Leaf("田七");
        Component leaf3 = new Leaf("阿莫西林");
        Component leaf4 = new Leaf("葡萄糖");
        root.AddChild(c1);
        root.AddChild(c2);
        c1.AddChild(leaf1);
        c1.AddChild(leaf2);
        c2.AddChild(leaf3);
        c2.AddChild(leaf4);
        root.print("");
    


运行结果为:
-中西药
 -中药
  -人参
  -田七
 -西药
  -阿莫西林
  -葡萄糖

  通过客户端代码可以看出,不用再区分操作的是树枝还是树叶构建了,客户端统一认为操作的是Component对象。

组合模式总结

  在使用组合模式的时候,比较关注的是透明性,因为使用组合模式主要就是为了让客户端不用再区分到底是树枝对象还是树叶对象,透明式的组合模式在安全方面虽然会有少许问题,尤其在类型转换的时候会造成类信息的丢失,但是在开发过程中这些操作都是可预见的,强制进行类型转换本身就是不够安全的做法。所以在使用组合模式的时候,还是尽量使用透明式的组合模式。

 

以上是关于java设计模式--组合模式的主要内容,如果未能解决你的问题,请参考以下文章

Java 设计模式系列组合模式

java设计模式之组合模式

java设计模式5.组合模式门面模式享元模式桥接模式

Java进阶篇设计模式之六 ----- 组合模式和过滤器模式

Java设计模式-组合模式

java设计模式 GOF23 09 组合模式