设计模式学习总结(十)--组合模式

定义

组合模式又叫部分-整体模式,组合多个对象形成树形结构以表示“整体-部分”的结构层次。

组合模式对单个对象(叶子对象)和组合对象(组合对象)具有一致性,它将对象组织到树结构中,可以用来描述整体与部分的关系。同时它也模糊了简单元素(叶子对象)和复杂元素(容器对象)的概念,使得客户能够像处理简单元素一样来处理复杂元素,从而使客户程序能够与复杂元素的内部结构解耦。

组合模式包含角色:

  • Component :组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理 Component 子部件。

  • Leaf:叶子对象。叶子结点没有子结点。

  • Composite:容器对象,定义有枝节点行为,用来存储子部件,在 Component 接口中实现与子部件有关操作,如增加(add)和删除(remove)等。

从模式结构中我们看出了叶子节点和容器对象都实现 Component 接口,这也是能够将叶子对象和容器对象一致对待的关键所在。

优缺点

优点:

  • 更容易在组合体内加入对象构件,客户端不必因为加入了新的对象构件而更改原有代码。

  • 可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件也更容易。

  • 客户端调用简单,客户端可以一致的使用组合结构或其中单个对象。

  • 定义了包含叶子对象和容器对象的类层次结构,叶子对象可以被组合成更复杂的容器对象,而这个容器对象又可以被组合,这样不断递归下去,可以形成复杂的树形结构。

缺点

  • 使设计变得更加抽象,对象的业务规则如果很复杂,则实现组合模式具有很大挑战性,而且不是所有的方法都与叶子对象子类都有关联

实例

以文件系统为例。

定义文件抽象类:

public abstract class File {

    public File(String name){
        this.name = name;
    }
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public abstract void display();
}

文本文件、图像文件、视频文件对象:

public class TestFile extends File {
    public TestFile(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("文本文件,文件名:" + super.getName());
    }
}

public class ImageFile extends File {
    public ImageFile(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("图像文件,文件名:" + super.getName());
    }
}

public class VideoFile extends File {
    public VideoFile(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("视频文件,文件名:" + super.getName());
    }
}

文件夹对象:

public class Folder extends File {

    private List<File> fileList = new ArrayList<>();

    public Folder(String name) {
        super(name);
    }

    /**
     * @desc 向文件夹中添加文件
     * @param file
     * @return void
     */
    public void add(File file){
        fileList.add(file);
    }

    /**
     * @desc 从文件夹中删除文件
     * @param file
     * @return void
     */
    public void remove(File file){
        fileList.remove(file);
    }
    /**
     * 浏览文件夹中的文件
     */
    @Override
    public void display() {
        for(File file : fileList){
            file.display();
        }
    }

}

调用:

public static void main(String[] args) {
    // 组装文本目录
    Folder testFolder = new Folder("文本目录");
    testFolder.add(new TestFile("文本文件1"));
    testFolder.add(new TestFile("文本文件2"));

    // 组装图片目录
    Folder imageFolder = new Folder("图片目录");
    imageFolder.add(new ImageFile("图片文件1"));
    imageFolder.add(new ImageFile("图片文件2"));

    // 组装视频目录
    Folder videoFolder = new Folder("视频目录");
    videoFolder.add(new VideoFile("视频文件1"));
    videoFolder.add(new VideoFile("视频文件2"));

    // 组装根目录
    Folder rootFolder = new Folder("根目录");
    rootFolder.add(testFolder);
    rootFolder.add(imageFolder);
    rootFolder.add(videoFolder);

    // 浏览目录
    System.out.println("=========浏览根目录=========");
    rootFolder.display();
    System.out.println("=========浏览文本目录=========");
    testFolder.display();
    System.out.println("=========浏览图片目录=========");
    imageFolder.display();
    System.out.println("=========浏览视频目录=========");
    videoFolder.display();
}

控制台输出:

=========浏览根目录=========
文本文件,文件名:文本文件1
文本文件,文件名:文本文件2
图像文件,文件名:图片文件1
图像文件,文件名:图片文件2
视频文件,文件名:视频文件1
视频文件,文件名:视频文件2
=========浏览文本目录=========
文本文件,文件名:文本文件1
文本文件,文件名:文本文件2
=========浏览图片目录=========
图像文件,文件名:图片文件1
图像文件,文件名:图片文件2
=========浏览视频目录=========
视频文件,文件名:视频文件1
视频文件,文件名:视频文件2
原文地址:https://www.cnblogs.com/markLogZhu/p/11582573.html