Rust语言之GoF设计模式:组合Composite模式


组合Composite属于一种树状结构的组成结构,这种结构属于繁杂Complicated,而不是复杂性的Complex,繁杂和复杂区别是:前者你可以控制它,花费时间和力气以及认真态度就能解决,而后者则是你无法认知它,因为它太复杂了,如同盲人摸象,你认识到只是事物的一个方面而已。

能用树形结构描述的结构我们需要将其繁杂性隐藏起来,不用暴露给每个接触或使用它的人,这是组合模式的目标所在。

以一个操作系统文件系统的例子来尝试理解组合模式。在文件系统中,有两种类型的对象:文件和文件夹。在某些情况下,文件和文件夹应该被视为相同的方式。
File并且Directory两者都拥有trait这样的接口特征:有一个search 方法。对于文件,它只会查看文件的内容;对于一个文件夹,它将遍历该文件夹的所有文件以找到该关键字,但是对于希望搜索的人,它是不知道search方法内部这种对文件和文件夹区别对待的能力,这样文件和文件夹的树形组合结构就不必暴露给每一个希望搜素的客户端。

Gof设计模式中,有一些功能希望让客户端调用者自由决定,客户端需要根据自己的上下文决定其调用对象;但是如果被调用对象很繁杂,如是一个大型组合树形结构,那么客户端会被自己调用的代码吓坏了,这时,它希望只是调用一个功能,也无所谓自己的上下文了。

我们首先要创建一个接口特征trait:
mod.rs

mod file;
mod folder;

pub use file::File;
pub use folder::Folder;

pub trait Component {
    fn search(&self, keyword: &str);
}

这个接口只提供一个简单搜索功能,当然,这个搜索的活做起来很复杂,调用者就没有必要知道,这是”无以为用“,当你看不到内部构造繁杂性以后,你就能轻松的使用它了,这有时也比喻外行做内行领导,有时还领导得挺好,只需要下命令即可。

繁杂代码如下:
folder.rs
file.rs

下面看看外行客户端是如何简单地下达调用命令的:
main.rs

mod fs;

use fs::{Component, File, Folder};

fn main() {
    let file1 = File::new("File 1");
    let file2 = File::new(
"File 2");
    let file3 = File::new(
"File 3");

    let mut folder1 = Folder::new(
"Folder 1");
    folder1.add(file1);

    let mut folder2 = Folder::new(
"Folder 2");
    folder2.add(file2);
    folder2.add(file3);
    folder2.add(folder1);

    folder2.search(
"rose");
}

输出:

Searching recursively for keyword rose in folder Folder 2
Searching for keyword rose in file File 2
Searching for keyword rose in file File 3
Searching recursively for keyword rose in folder Folder 1
Searching for keyword rose in file File 1

可以看出,外行领导频繁下达各种搜索指令,整得手下人仰马翻,但是他达到了”无以为用“的境界。

当然,内行手下可能不服,”有以为利“,有了一套应对繁杂树形结构的技术活,自己觉得很利害,会跳槽走人。

所以,无以为用 + 有以为利 = 战略 + 战术 配合才能做赢家,这是团队合作的重要性。