Java实现组合模式:一步步指南

发表时间: 2024-05-17 11:17

定义


组合模式最初只是用于解决树形结构的场景,更多的是处理对象组织结构之间的问题。而组合关系则是通过将不同对象封装起来完成一个统一功能


组合模式(composite pattern)的定义是:将对象组合成树形结构以表示整个部分的层次结构。组合模式可以让用户统一对待单个对象和对象的组合


结构图



案例演示


列出某一目录下所有的文件和文件夹



代码


/** * @Description: 抽象类(文件夹+文件) * @author: zhuoyue * @since: 2024/05/13 15:32 */public abstract class Entry {    public abstract String getName();    public abstract int getSize();    /**     * 添加文件或文件夹     * @param entry     * @return     */    public abstract Entry add(Entry entry);    /**     * 显示指定目录下的所有文件的信息     * @param entry     */    public abstract void printList(String entry);    @Override    public String toString() {        return getName()+"("+getSize()+")";    }}public class File extends Entry{    private String name;    private int size;    public File(String name, int size) {        this.name = name;        this.size = size;    }    @Override    public String getName() {        return name;    }    @Override    public int getSize() {        return size;    }    @Override    public Entry add(Entry entry) {        return null;    }    @Override    public void printList(String entry) {        System.out.println(entry+"/"+this);    }    public void setSize(int size) {        this.size = size;    }}public class Directory extends Entry{    private String name;    private ArrayList<Entry> directory = new ArrayList<>();    public Directory(String name) {        this.name = name;    }    @Override    public String getName() {        return null;    }    @Override    public int getSize() {        int size = 0;        for (Entry entry: directory){            size += entry.getSize();        }        return size;    }    @Override    public Entry add(Entry entry) {        directory.add(entry);        return this;    }    @Override    public void printList(String prefix) {        System.out.println(prefix+"/"+this);        for (Entry entry: directory){            entry.printList(prefix+"/"+name);        }    }}public class Client {    public static void main(String[] args) {        /**         * 根节点         */        Directory rootDir = new Directory("root");        /**         * 树枝节点         */        Directory binDir = new Directory("bin");        binDir.add(new File("vi",10000));        binDir.add(new File("test",20000));        Directory tmpDir = new Directory("tmp");        Directory usrDir = new Directory("usr");        Directory mysqlDir = new Directory("mysql");        mysqlDir.add(new File("my.cnf",30));        mysqlDir.add(new File("test.db",25000));        usrDir.add(mysqlDir);        rootDir.add(mysqlDir);        rootDir.add(binDir);        rootDir.add(tmpDir);        rootDir.add(usrDir);        rootDir.printList("");    }}



总结


  • 组合模式分类


  1. 透明组合模式


在透明组合模式中,抽象根节点橘色中声明了所有用于管理成员对象的方法。


缺点是不够安全,因为叶子对象和容器对象本质上还是有区别的,叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供add()、remove()等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用者这些方法可能会出错,(可以抛出异常)

2. 安全组合模式


在抽象构件角色中不声明任何用于管理成员对象的方法,而是在树枝节点类中声明并实现这些方法。安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件中定义,因此客户端不能完全针对抽象编程,必须有区别的针对叶子构件和容器构件


  • 优点


  1. 组件模式可以清楚的定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
  2. 客户端可以一致的使用一个组合结构或其中单个对象,不必关心处理的结构是单个对象还是整个组织结构,简化了客户端代码。
  3. 在组合模式中增加新的树枝节点或叶子节点都很方便,无须对现有类库进行任何修改,符合“开闭原则”
  4. 组合模式为树形结构对象实现提供了一种灵活的解决方案,通过叶子节点和树枝节点的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单


  • 缺点


  1. 使用组合模式的前提在于你的业务场景是否能够表示成树形结构。所以组合模式的应用场景也比较局限,所以它并不是一种很常用的设计模式


  • 应用场景


  1. 处理一个树形结构,比如,公司人员组织架构、订单信息等
  2. 跨越多个层次结构聚合数据,比如,统计文件夹下的文件总数
  3. 统一处理一个结构中的多个对象,比如遍历文件夹下的所有XML类型文件内容