组合模式

概念

组合模式(Composite Pattern),又叫 “部分整体” 模式,将对象组合成树形结构,以表示 “部分-整体” 的层次结构。通过对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性.

UML图

compositepattern.jpg

具体实现

有3种角色对象,

  1. 根节点
  2. 树枝节点(组合节点), 可以向下包含树枝节点和叶子结点
  3. 叶子节点, 最底层的节点

代码实现

  1. 定义一个所有节点统一的Component操作接口, 方法包含添加节点,遍历节点, 节点名称设置,获取。
  2. 定义一个节点生成工厂结构体, 成员变量为节点名称,实现Component接口, 通过传入不同的节点字段,得到不同的节点实例。
  3. 定义一个树枝节点, 节点继承工厂结构体, 通过嵌套匿名工厂结构体的方式, 内部成员Component 切片, 覆盖添加节点和遍历节点方法
  4. 定义一个叶子节点, 节点继承工厂结构体, 覆盖打印名称节点。

模式的场景和优缺点

使用场景

组合模式应树形结构而生,所以组合模式的使用场景就是出现树形结构的地方:

「命令分发:」 只需要通过请求树的最顶层对象,便能对整棵树做统一的操作。在组合模式中增加和删除树的节点非常方便,并且符合开放-封闭原则;

「统一处理:」 统一对待树中的所有对象,忽略组合对象和叶对象的区别

特点

composite.jpg
  • 表示 “部分-整体” 的层次结构,生成 "树叶型" 结构
  • 操作一致操作性,所有节点操作具有一致性。
  • 自上而下的的请求流向,从树对象传递给叶对象
  • 调用顶层对象,会自行遍历其下的叶对象执行
  • 组合模式的遍历, 本质上是一种递归的代码结构

优点

  • 高层模块调用简单
  • 节点自由增加

缺点

  • .

代码实现


package main

import (
    "fmt"
)

// Component 所有节点的操作接口
type Component interface {
    GetName() string
    SetName(string)
    AddChild(Component)
    Print(string)
}

const (
    // LeafNode ...
    LeafNode = iota
    // CompositeNode ...
    CompositeNode
)

// NewComponent 生成节点, 节点生成工厂
func NewComponent(kind int, name string) Component {
    var c Component
    switch kind {
    case LeafNode:
        // 叶子
        c = NewLeaf()
    case CompositeNode:
        // 根
        c = NewComposite()
    }
    c.SetName(name)
    return c
}

// component ...它实现了component接口,树枝节点(组合节点)和叶子节点通过嵌套匿名匿名结构体的方式实现了继承
// 除了叶子结点和树枝节点特有的功能需要单独实现。
type component struct {
    name string
}

// Name ...
func (c *component) GetName() string {
    return c.name
}

// SetName ...
func (c *component) SetName(name string) {
    c.name = name
}

// AddChild 根才能添加孩子节点,根会实现
func (c *component) AddChild(Component) {}

func (c *component) Print(string) {}

// Leaf ...
type Leaf struct {
    component
}

// NewLeaf ...
func NewLeaf() *Leaf {
    return &Leaf{}
}

// Print ...
func (c *Leaf) Print(pre string) {
    fmt.Printf("%s-%s\n", pre, c.GetName())
}

// Composite ...
type Composite struct {
    component
    childs []Component
}

// NewComposite ...
func NewComposite() *Composite {
    return &Composite{
        childs: make([]Component, 0),
    }
}

// AddChild 根才能添加孩子节点
func (c *Composite) AddChild(child Component) {
    c.childs = append(c.childs, child)
}

// Print ...
func (c *Composite) Print(pre string) {
    fmt.Printf("%s+%s\n", pre, c.GetName())
    pre += " "
    for _, comp := range c.childs {
        comp.Print(pre)
    }
}

func main() {

    root := NewComponent(CompositeNode, "root")
    c1 := NewComponent(CompositeNode, "c1")
    c2 := NewComponent(CompositeNode, "c2")
    c3 := NewComponent(CompositeNode, "c3")

    l1 := NewComponent(LeafNode, "l1")
    l2 := NewComponent(LeafNode, "l2")
    l3 := NewComponent(LeafNode, "l3")

    // 树状结构
    root.AddChild(c1)
    root.AddChild(c2)
    c1.AddChild(c3)
    c1.AddChild(l1)
    c2.AddChild(l2)
    c2.AddChild(l3)

    root.Print("")
}

// root.Print("")
// 输入结果如下, 第一个root 非 child, 直接打印。 后面的打印顺序和添加顺序不同, +c1 +c3 -l1 ,调用到c1 child的时候,
// 又是一个新的c1的child列表,Print会调用到c1的子 child, 这里的存在一个Print的递归调用。
/*
   +root
    +c1
     +c3
     -l1
    +c2
     -l2
     -l3
*/

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容