Java设计模式——组合模式

组合模式

介绍
意图:将对象组合成树形结构以表示”部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

何时使用: 1、您想表示对象的部分-整体层次结构(树形结构)。 2、您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

如何解决:树枝和叶子实现统一接口,树枝内部组合该接口。

关键代码:树枝内部组合该接口,并且含有内部属性 List,里面放 Component。

应用实例: 1、算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作符也可以是操作数、操作符和另一个操作数。 2、在 JAVA AWT 和 SWING 中,对于 Button 和 Checkbox 是树叶,Container 是树枝。

优点: 1、高层模块调用简单。 2、节点自由增加。

缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。

注意事项:定义时为具体类。
https://www.cnblogs.com/lfxiao/p/6816026.html

abstract class Component {  
    public abstract void add(Component c); //增加成员 
    public abstract void remove(Component c); //删除成员 
    public abstract Component getChild(int i); //获取成员 
    public abstract void operation();  //业务方法 
}  
class Leaf extends Component {  
    public void add(Component c) {   
        //异常处理或错误提示 
    }     
          
    public void remove(Component c) {   
        //异常处理或错误提示 
    }  
      
    public Component getChild(int i) {   
        //异常处理或错误提示 
        return null;   
    }  
      
    public void operation() {  
        //叶子构件具体业务方法的实现 
    }   
}
class Composite extends Component {  
    private ArrayList<Component> list = new ArrayList<Component>();  
      
    public void add(Component c) {  
        list.add(c);  
    }  
      
    public void remove(Component c) {  
        list.remove(c);  
    }  
      
    public Component getChild(int i) {  
        return (Component)list.get(i);  
    }  
      
    public void operation() {  
        //容器构件具体业务方法的实现 
        //递归调用成员构件的业务方法 
        for(Object obj:list) {  
            ((Component)obj).operation();  
        }  
    }     
} 

透明组合模式与安全组合模式

通过引入组合模式,Sunny公司设计的杀毒软件具有良好的可扩展性,在增加新的文件类型时,无须修改现有类库代码,只需增加一个新的文件类作为AbstractFile类的子类即可,但是由于在AbstractFile中声明了大量用于管理和访问成员构件的方法,例如add()、remove()等方法,我们不得不在新增的文件类中实现这些方法,提供对应的错误提示和异常处理。为了简化代码,我们有以下两个解决方案:

透明组合模式:将叶子构件的add()、remove()等方法的实现代码移至AbstractFile类中,由AbstractFile提供统一的默认实现,代码如下所示:

//提供默认实现的抽象构件类 
abstract class AbstractFile {  
    public void add(AbstractFile file) {  
        System.out.println("对不起,不支持该方法!");  
    }  
      
    public void remove(AbstractFile file) {  
        System.out.println("对不起,不支持该方法!");  
    }  
      
    public AbstractFile getChild(int i) {  
        System.out.println("对不起,不支持该方法!");  
        return null;  
    }  
      
    public abstract void killVirus();  
}  

如果客户端代码针对抽象类AbstractFile编程,在调用文件对象的这些方法时将出现错误提示。如果不希望出现任何错误提示,我们可以在客户端定义文件对象时不使用抽象层,而直接使用具体叶子构件本身,客户端代码片段如下所示:

class Client {  
    public static void main(String args[]) {  
        //不能透明处理叶子构件 
        ImageFile file1,file2;  
        TextFile file3,file4;  
        VideoFile file5;  
        AbstractFile folder1,folder2,folder3,folder4;  
        //其他代码省略 
      }  
}  

这样就产生了一种不透明的使用方式,即在客户端不能全部针对抽象构件类编程,需要使用具体叶子构件类型来定义叶子对象。

安全组合模式:除此之外,还有一种解决方法是在抽象构件AbstractFile中不声明任何用于访问和管理成员构件的方法,代码如下所示:

abstract class AbstractFile {  
    public abstract void killVirus();  
} 

此时,由于在AbstractFile中没有声明add()、remove()等访问和管理成员的方法,其叶子构件子类无须提供实现;而且无论客户端如何定义叶子构件对象都无法调用到这些方法,不需要做任何错误和异常处理,容器构件再根据需要增加访问和管理成员的方法,但这时候也存在一个问题:客户端不得不使用容器类本身来声明容器构件对象,否则无法访问其中新增的add()、remove()等方法,如果客户端一致性地对待叶子和容器,将会导致容器构件的新增对客户端不可见,客户端代码对于容器构件无法再使用抽象构件来定义,客户端代码片段如下所示:

class Client {  
    public static void main(String args[]) {  
        AbstractFile file1,file2,file3,file4,file5;  
        Folder folder1,folder2,folder3,folder4; //不能透明处理容器构件 
        //其他代码省略 
    }  
}

你可能感兴趣的:(Java设计模式——组合模式)