一架梯子,一头程序猿,仰望星空!
Golang设计模式教程 > 内容正文

Golang组合模式


一、什么是组合模式

组合模式(Composite Pattern)是一种常用的对象结构型设计模式。它是将对象组合成树状结构以表示“部分-整体”的层次结构,使得客户端以一致的方式处理单个对象和对象组合。

二、组合模式的特点和优点

组合模式的主要优点有:

  1. 可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件也更容易。
  2. 提供一个统一的接口,使得访问组合部分和单个对象的接口一致,使客户端对单个对象和组合对象的使用是一致的。

三、组合模式的应用场景

  1. 你希望表示对象的部分-整体层次
  2. 你希望客户忽略组合对象与单个对象的不同,客户将统一的使用组合结构中的所有对象。

四、Golang中的组合模式实现

假设我们在设计一个电商应用,商品目录就是一个很好的组合模式例子。一个类别可以包含其他类别,也可以包含商品(如电子类别包含了手机,电脑,而手机又包含了苹果手机,三星手机等)。

4.1 UML类图

Golang组合模式

4.2 示例介绍

在这个例子里,我们有Component(明显利用到面向对象的接口特性)作为抽象基类,CompositeLeaf都实现该接口,它们分别代表容器对象和基本对象。

4.3 实现步骤1: 定义抽象组件类

这个方法通常在接口类定义,并且是关键的中心操作。

4.3.1 定义抽象组件类接口

//Component : 基础组件接口,定义了群体和个体的共性
type Component interface {
    Search(string)
}

4.3.2 实现抽象组件类基本方法

这个步骤函数具体在容器组件类和叶子组件类实现。

4.4 实现步骤2: 定义叶子组件类

这个具体类代表层次中的底部类别或对象,它没有下一层的对象。

4.4.1 继承抽象组件类

在Go中,interface的继承通过Struct实现方法的方式。

4.4.2 实现叶子组件类特有方法

//Product : 代表叶子节点,即商品,不能有子节点
type Product struct {
    Name string
}

//Search : 搜索商品
func (p *Product) Search(keyword string) {
    if strings.Contains(p.Name, keyword) {
        fmt.Printf("Product: '%s' contains keyword: '%s'\n", p.Name, keyword)
    }
}

4.5 实现步骤3: 定义容器组件类

这个类用于存储和管理子对象,一般包含一些管理和组织子对象的方法,如add(Component), remove(Component)等。

4.5.1 继承抽象组件类

这同样通过Go的Struct实现接口方法实现。

4.5.2 实现容器组件类特有方法

//Category : 代表容器节点,即商品类别,可以有子节点
type Category struct {
    Name     string
    Children []Component
}

//Add 添加子节点
func (c *Category) Add(child Component) {
    c.Children = append(c.Children, child)
}

//Remove 删除子节点
func (c *Category) Remove(child Component) {
    //具体实现略
}

//Search 搜索商品
func (c *Category) Search(keyword string) {
    fmt.Printf("Category: %s\n", c.Name)
    for _, composite := range c.Children {
        composite.Search(keyword)
    }
}

4.6 实现步骤4: 客户端代码示例

实例化一个结构体,组装成一个树形结构,然后调用树形结构的访问操作。

func main() {
    root := &Category{Name: "Root"}
    electronics := &Category{Name: "Electronics"}

    phone := &Product{Name: "Phone"}
    tv := &Product{Name: "Television"}

    root.Add(electronics)
    electronics.Add(phone)
    electronics.Add(tv)

    root.Search("phone") // This will search in all children
}