美文网首页设计模式
小白设计模式:组合模式

小白设计模式:组合模式

作者: CodeInfo | 来源:发表于2018-11-29 11:43 被阅读0次

    定义

    将对象组合成树形结构来表现出“整体/部分”的层次结构。组合能让客户以一致性的方式处理个别的对象以及对象组合。

    主要组成

    抽象组件(Component): 为组合中的对象(节点或者组件)声明接口,也可提供默认的接口缺省实现;

    节点对象(Leaf): 组合中的叶节点对象,叶节点对象不再拥有子节点;

    复合对象(Composite):允许存在多个子部件,需要包含的子部件,并实现对子部件的操作接口;

    客户端(Client): 调用端,通过调用Component相关接口,操作组合中的对象;

    UML图

    image image

    透明模式:叶节点和组合对象所拥有的操作都放抽象组件Component,这样客户端调用时,不需要判断节点类型都可以进行api调用,无需类型转换。但是对应的存在安全性的问题,因为叶节点本身并不具备组合对象add、remove、get等等有关子节点的操作api,这样的设计可能导致调用后出现与预期不符的现象,因为客户有可能会做一些无意义
    的事情,例如在Leaf 中增加和删除对象等。

    安全模式:将组合对象独有的api操作都放在对应的实现类中,好处就是安全性提升,只有组合对象才会提供add、remove、get等操作。缺点就是不够透明,整个树形结构元素使用上,因为Leaf 和Composite具有不同的接口,客户还得区分判断是叶节点或者组合对象,并进行类型转换才可以调用相应的api;

    2种方式在于透明性和安全性的互换,这需要在安全性和透明性之间做出权衡选择,在这一模式中,相对于安全性,我们比较强调透明性。如果你选择了安全性,有时你可能会丢失类型信息,并且不得不将一个组件转换成一个组合。这样的类型转换必定不是类型安全的。

    框架代码

    这边以透明模式为例:

    抽象组件(Component):

    将默认实现为抛出异常(也可空实现之类的,具体情况具体分析),子类根据需要进行重写

    public abstract class Component {
        public abstract void operation();
        public void add(Component component) {
            throw new UnsupportedOperationException();
        }
    
        public void remove(Component component) {
            throw new UnsupportedOperationException();
        }
        public Component get(int index) {
            throw new UnsupportedOperationException();
        }
    }
    

    节点对象(Leaf):

    public class Leaf extends Component{
        @Override
        public void operation() {
            //...
            System.out.println("叶节点自身的操作");
        }
    }
    

    复合对象(Composite):

    public class Composite extends Component{
        
        List<Component> components = new ArrayList<Component>();
    
        @Override
        public void add(Component component) {
            components.add(component);
        }
    
        @Override
        public void remove(Component component) {
            components.remove(component);
        }
    
        @Override
        public Component get(int index) {
            return components.get(index);
        }
    
        @Override
        public void operation() {
            for (Component component : components) {
                component.operation();
            }
        }   
    }
    

    Client中调用:

        //创建过程一般是对调用端隐藏,Client不需要关系是创建的什么对象
        Component component = new Composite();
        Component leaf1 = new Leaf();
        Component leaf2 = new Leaf();
        component.add(leaf1);
        
        List<Component> list = new ArrayList<>();
        list.add(component);
        list.add(leaf2);
        
        //Client只要执行自己所需要的操作就行
        for (Component component : list) {
            component.operation();
        }
        
    

    具体例子

    熟悉的windows文件目录结构就可以看出是组合模式中的树状图。节点可以是文件(Leaf),也可以是目录(Compostite),可以定义出共同的抽象组件(Component)提供接口: open、delete等相关文件操作。

    UML图

    image

    代码

    AbstractFile抽象文件(Component):

    public abstract class AbstractFile {
        String fileName;
        
        public AbstractFile(String fileName) {
            this.fileName = fileName;
        }
        
        public abstract void open();
        public abstract void delete();
        public abstract boolean isDirect();
        
        public void add(AbstractFile abstractFile) {
            throw new UnsupportedOperationException();
        }
    
        public void remove(AbstractFile abstractFile) {
            throw new UnsupportedOperationException();
        }
        public AbstractFile get(int index) {
            throw new UnsupportedOperationException();
        }
    }
    

    File文件叶节点(Leaf):

    public class File extends AbstractFile{
    
        public File(String fileName) {
            super(fileName);
        }
    
        @Override
        public void open() {
            System.out.println("打开文件" + fileName);
            
        }
    
        @Override
        public void delete() {
            System.out.println("删除文件" + fileName);
        }
        
        @Override
        public boolean isDirect() {
            return false;
        }
    }
    

    Directory目录节点(Composite)

    public class Directory extends AbstractFile{
    
        List<AbstractFile> files = new ArrayList<>();
        
        public Directory(String fileName) {
            super(fileName);
        }
        
        @Override
        public void add(AbstractFile abstractFile) {
            files.add(abstractFile);
        }
    
        @Override
        public void remove(AbstractFile abstractFile) {
            files.remove(abstractFile);
        }
    
        @Override
        public AbstractFile get(int index) {
            return files.get(index);
        }
    
    
    
        @Override
        public void open() {
            for (AbstractFile abstractFile : files) {
                abstractFile.open();
            }
        }
    
        @Override
        public void delete() {
            for (AbstractFile abstractFile : files) {
                abstractFile.delete();
            }
        }
    
        @Override
        public boolean isDirect() {
            return true;
        }
    }
    

    客户端调用

    假设进行文件删除:

    AbstractFile directory = new Directory("目录");
    AbstractFile file1 = new File("文件1");
    AbstractFile file2 = new File("文件2");
    directory.add(file1);
    
    List<AbstractFile> list = new ArrayList<>();
    list.add(directory);
    list.add(file2);
    
    for (AbstractFile abstractFile : list) {
        abstractFile.delete();
    }
    

    假设不使用组合模式

    已上诉文件目录例子为例,则会导致在一个文件集合中需要针对性的判断该文件类型:

    Directory directory = new Directory("目录");
    File file1 = new File("文件1");
    File file2 = new File("文件2");
    
    List<Object> list = new ArrayList<>();
    list.add(directory);
    list.add(file1);
    list.add(file2);
    
    for (Object object : list) {
        if (object instanceof File) {
            //....
        }
        if (object instanceof Directory) {
            //....
        }
    }
    

    总结

    优点

    使得使用方能够以一致性的方式调用接口,来处理对象,而不必关心这个对象是单个叶节点还是一个组合的对象结构。

    缺点

    安全性与透明性的考虑

    应用场景

    有一系列对象集合,并且这些对象集合有明显的"整体/部分"的关系,可以构建成树形结构。

    微信公众号

    image

    相关文章

      网友评论

        本文标题:小白设计模式:组合模式

        本文链接:https://www.haomeiwen.com/subject/wnixcqtx.html