1.组合模式的定义

        将对象组合成树形结构以表示整个部分的层次结构,组合模式可以让用户统一对待单个对象和对象的组合;其更像是一种数据结构和算法的抽象,其中数据可以表示成树这种数据结构,业务需求可以通过在树上的递归遍历算法来实现;

1.1 组合模式优缺点

优点

  • 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。

  • 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。

  • 在组合模式中增加新的树枝节点和叶子节点都很方便,无须对现有类库进行任何修改,符合“开闭原则”。

  • 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子节点和树枝节点的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

缺点

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

1.2 组合模式的使用场景

  • 处理一个树形结构,比如,公司人员组织架构、订单信息等;

  • 跨越多个层次结构聚合数据,比如,统计文件夹下文件总数;

  • 统一处理一个结构中的多个对象,比如,遍历文件夹下所有 XML 类型文件内容。

2.组合模式原理

  • 抽象根节点(Component):定义系统各层次对象的共有方法和属性,可以预先定义一些默认行为和属性;
  • 树枝节点(Composite):定义树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成一个树形结构;
  • 叶子节点(Leaf):叶子节点对象,没有子节点,是系统层次遍历的最小单位;

3.组合模式的实现

【实例】

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

【代码】

        Entry类,抽象类,用来定义File类与Directory类的共性内容

public abstract class Entry {

    public abstract String getName(); //获取文件名
    public abstract int getSize(); //获取文件大小
    //添加文件夹或文件
    public abstract Entry add(Entry entry);
    //显示指定目录下的所有信息
    public abstract void printList(String prefix);
    @Override
    public String toString() {
        return getName() + "(" +getSize() + ")";
    }
}

         File类,叶子节点,表示文件

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 prefix) {
        System.out.println(prefix + "/" + this);
    }
}

        Directory类,树枝节点,表示文件

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 this.name;
    }

    /**
     * 获取文件大小
     *      1.如果entry对象是File类型,则调用getSize方法获取文件大小
     *      2.如果entry对象是Directory类型,会继续调用子文件夹的getSize方法,形成递归调用.
     */
    @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("/" + this);
        for (Entry entry : directory) {
            entry.printList("/" + name);
        }
    }
}

        客户端

//根节点
Directory rootDir = new Directory("root");

//树枝节点
Directory binDir = new Directory("bin");
//向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(binDir);
rootDir.add(tmpDir);
rootDir.add(mysqlDir);

rootDir.printList("");

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部