结构型 - 6. 组合模式

124 阅读2分钟

组合模式(Composite Design)跟我们之前讲的面向对象设计中的“组合关系(通过组合来组装两个类)”,完全是两码事。这里讲的“组合模式”,主要是用来处理树形结构数据。这里的“数据”,你可以简单理解为一组对象集合,待会我们会详细讲解。

正因为其应用场景的特殊性,数据必须能表示成树形结构,这也导致了这种模式在实际的项目开发中并不那么常用。但是,一旦数据满足树形结构,应用这种模式就能发挥很大的作用,能让代码变得非常简洁。

1. 组合模式的原理

将一组对象组织(Compose)成树形结构,以表示一种“部分 - 整体”的层次结构。组合让使用者可以统一单个对象和组合对象的处理逻辑

Compose objects into tree structure to represent part-whole hierarchies.Composite lets client treat individual objects and compositions of objects uniformly.

以文件和目录为例。将一组对象(文件和目录)组织成树形结构,以表示一种‘部分 - 整体’的层次结构(目录与子目录的嵌套结构)。组合模式让客户端可以统一单个对象(文件)和组合对象(目录)的处理逻辑(递归遍历)。

这种组合模式的设计思路,与其说是一种设计模式,倒不如说是对业务场景的一种数据结构和算法的抽象。其中,数据可以表示成树这种数据结构,业务需求可以通过在树上的递归遍历算法来实现。

2. 组合模式的应用场景

组合模式,将一组对象组织成树形结构,将单个对象和组合对象都看做树中的节点,以统一处理逻辑,并且它利用树形结构的特点,递归地处理每个子树,依次简化代码实现。

典型例子:文件与目录、部分与员工。

3. 组合模式的代码实现


type FileSystemNode interface {
   search(keyword string)
}

type File struct {
   name string
}

func (f *File) search(keyword string) {
   fmt.Printf("Searching for keyword %s in file %s\n", keyword, f.name)

}

type Folder struct {
   name  string
   nodes []FileSystemNode
}

func (f *Folder) addNode(node FileSystemNode) {
   f.nodes = append(f.nodes, node)
}

func (f *Folder) search(keyword string) {
   fmt.Printf("Serching recursively for keyword %s in folder %s\n", keyword, f.name)
   for _, node := range f.nodes {
      node.search(keyword)
   }
}

// 客户端代码
func TestNode(t *testing.T) {
   file1 := &File{name: "File1"}
   file2 := &File{name: "File2"}
   file3 := &File{name: "File3"}
   folder1 := &Folder{
      name: "Folder1",
   }
   folder1.addNode(file1)
   folder2 := &Folder{
      name: "Folder2",
   }
   folder2.addNode(file2)
   folder2.addNode(file3)
   folder2.addNode(folder1)
   folder2.search("rose")
}