组合模式-统一的处理个别对象与组合对象

公号:码农充电站pro
主页:https://codeshellme.github.io

本篇来介绍组合模式Composite Design Pattern)。

1,组合模式

组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。

如果对象之间呈树形结构,是一种部分与整体的关系,这种情况都比较适合用组合模式。

组合模式构建的树状关系如下所示:

在这里插入图片描述

组合模式使得我们构建这种树状关系变得极为简单。aComposite 是组合对象,aLeaf 是个体对象。组合对象中可以嵌套组合对象和个体对象,个体对象中不能再包含其它对象。

因为组合对象中可以再次嵌套组合对象,所以组合模式也是一种递归关系

组合模式的类图如下:

在这里插入图片描述

从类图中可以看到,Component 为所有的对象提供了统一的接口。组合对象中有 addremove 操作,说明组合对象中可以添加和删除组合对象与个体对象。

注意 Leaf 节点中只有 operation 操作,因为 Leaf 节点不能再嵌套其它节点。

组合对象和个体对象中都有 operation 操作,使得我们能够把相同的操作应用在组合对象和个别对象上。

2,组合模式示例

下面举个例子,来看下如何使用组合模式。

我们已经知道,组合模式非常适合表示树形结构,而 Linux 目录结构就是一个树形结构。下面就用组合模式来构建目录结构。

我们知道目录中即可包含目录,也可包含文件。根据组合模式的类图,可设计出下面的 Linux 文件系统类图:

在这里插入图片描述

文件系统可以包括文件和目录,目录中可以嵌套目录和文件,而文件中不能再嵌套其它东西。所以,File 类中没有 addremove 方法。

首先创建 FileSystem 抽象类:

abstract class FileSystem {
    protected String path;

    public abstract void printFile();
}

printFile 方法用于输出文件名。

再创建 File 类:

class File extends FileSystem {
    public File(String path) {
        this.path = path;
    }

    public void printFile() {
        System.out.println(path);
    }
}

File 类继承了 FileSystem, 因为 File 类本身就是文件,所以它的 printFile 非常简单。

再创建 Directory 类:

class Directory extends FileSystem {
    private List<FileSystem> nodes; // 用于存储节点

    public Directory(String path) {
        this.path = path;
        this.nodes = new ArrayList<>();
    }

    public void printFile() {
        System.out.println(path);

		// 递归输出目录和文件
        for (FileSystem node: nodes) {
            node.printFile();
        }
    }

    public void addNode(FileSystem node) {
        nodes.add(node);
    }

    public void removeNode(FileSystem node) {
        nodes.remove(node);
    }
}

注意区分 File 类和 Directory 类的不同。

下面来测试代码,假设我们要构建这样的目录结构:

test/
├── a
├── b
│   ├── 1.txt
│   └── d
│       └── 2.txt
└── c
    └── 3.txt

首先创建文件节点和目录节点:

// 创建文件节点
File txt1 = new File("test/b/1.txt");
File txt2 = new File("test/b/d/2.txt");
File txt3 = new File("test/c/3.txt");

// 创建目录节点
Directory test = new Directory("test/");
Directory a = new Directory("test/a/");
Directory b = new Directory("test/b/");
Directory c = new Directory("test/c/");
Directory d = new Directory("test/b/d/");

构建目录结构:

// 构造目录结构
test.addNode(a);
test.addNode(b);
test.addNode(c);

b.addNode(txt1);
b.addNode(d);

c.addNode(txt3);
d.addNode(txt2);

输出 test 目录:

test.printFile();

结果如下:

test/
test/a/
test/b/
test/b/1.txt
test/b/d/
test/b/d/2.txt
test/c/
test/c/3.txt

输出 b 目录:

b.printFile();

结果如下:

test/b/
test/b/1.txt
test/b/d/
test/b/d/2.txt

删除 b 目录后,在输出 test 目录:

test.removeNode(b);
test.printFile();

结果如下:

test/
test/a/
test/c/
test/c/3.txt

通过测试结果可以看到,我们构建的目录结构是没有问题的。

我将完整的代码放在了这里,供大家参考。

3,总结

组合模式将一组对象组织成树形结构,对象分为个体对象和组合对象,组合对象中可以包含个体对象和组合对象。组合模式会以递归的方式来处理树的节点。

使用组合模式的前提是,对象之间的关系要符合树形结构的特点。组合模式使得处理树形结构的对象关系变得非常简单。

(本节完。)

推荐阅读:

外观模式-简化子系统的复杂性

模板方法模式-封装一套算法流程

迭代器模式-统一集合的遍历方式

状态模式-将状态和行为封装成对象

代理模式-访问对象的代理而非其本身

欢迎关注作者公众号,获取更多技术干货。

码农充电站pro

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结