结构型模式-组合模式
组合模式
组合是一种结构型设计模式, 你可以使用它将对象组合成 树状结构,并且能像使用独立对象一样使用它们
- 组件(Component)接口描述了树中简单项目和复杂项目所 共有的操作
- 叶节点(Leaf)是树的基本结构,它不包含子项目。 一般情况下,叶节点最终会完成大部分的实际工作,因为它 们无法将工作指派给其他部分。
- 容器(Container)——又名“组合(Composite)”——是包含叶 节点或其他容器等子项目的单位。容器不知道其子项目所属 的具体类,它只通过通用的组件接口与其子项目交互。容器接收到请求后会将工作分配给自己的子项目,处理中间 结果,然后将最终结果返回给客户端
- 客户端(Client)通过组件接口与所有项目交互。因此,客 户端能以相同方式与树状结构中的简单或复杂项目交互
Example
组件接口
package main
type Component interface { search(string) }
|
组合
package main
import "fmt"
type Folder struct { components []Component name string }
func (f *Folder) search(keyword string) { fmt.Printf("Serching recursively for keyword %s in folder %s\n", keyword, f.name) for _, composite := range f.components { composite.search(keyword) } }
func (f *Folder) add(c Component) { f.components = append(f.components, c) }
|
叶子
package main
import "fmt"
type File struct { name string }
func (f *File) search(keyword string) { fmt.Printf("Searching for keyword %s in file %s\n", keyword, f.name) }
func (f *File) getName() string { return f.name }
|
客户端
package main
func main() { file1 := &File{name: "File1"} file2 := &File{name: "File2"} file3 := &File{name: "File3"}
folder1 := &Folder{ name: "Folder1", }
folder1.add(file1)
folder2 := &Folder{ name: "Folder2", } folder2.add(file2) folder2.add(file3) folder2.add(folder1)
folder2.search("rose") }
|
适用场景
- 如果你需要实现树状对象结构,可以使用组合模式
- 组合模式为你提供了两种共享公共接口的基本元素类型:简 单叶节点和复杂容器。 容器中可以包含叶节点和其他容器。 这使得你可以构建树状嵌套递归对象结构
- 如果你希望客户端代码以相同方式处理简单和复杂元素,可 以使用该模式。
- 组合模式中定义的所有元素共用同一个接口。在这一接口的 帮助下,客户端不必在意其所使用的对象的具体类
优缺点
优点
- 利用多态和递归机制更方便地使用复杂树结构
- 开闭原则。无需更改现有代码,你就可以在应用中添加新元 素,使其成为对象树的一部分
缺点
- 对于功能差异较大的类,提供公共接口或许会有困难。在特 定情况下,你需要过度一般化组件接口,使其变得令人难以理解
与其他模式的关系
- 桥接、状态和策略(在某种程度上包括适配器)模式的接口 非常相似。实际上,它们都基于组合模式——即将工作委派 给其他对象,不过也各自解决了不同的问题。模式并不只是 以特定方式组织代码的配方,你还可以使用它们来和其他开 发者讨论模式所解决的问题
- 你可以在创建复杂组合树时使用生成器,因为这可使其构造 步骤以递归的方式运行
- 责任链通常和组合模式结合使用。在这种情况下,叶组件接 收到请求后,可以将请求沿包含全体父组件的链一直传递至 对象树的底部
- 可以使用迭代器来遍历组合树。
- 你可以使用访问者对整个组合树执行操作
- 你可以使用享元实现组合树的共享叶节点以节省内存。
- 组合和装饰的结构图很相似,因为两者都依赖递归组合来组 织无限数量的对象
- 大量使用组合和装饰的设计通常可从对于原型的使用中获益。 你可以通过该模式来复制复杂结构,而非从零开始重新构造