结构型设计模式—组合模式

发布时间:2024年01月04日

组合模式:通过将单个对象(叶子节点)和组合对象(树枝节点)用相同的接口进行表示,使得客户对单个对象和组合对象的使用具有一致性

组合模角色构成:

  1. 组件 (Component): 组件是一个接口,描述了树中单个对象和组合对象都要实现的的操作。
  2. 叶节点 (Leaf) :即单个对象节点,是树的基本结构, 它不包含子节点,因此也就无法将工作指派给下去,叶节点最终会完成大部分的实际工作。
  3. 组合对象 (Composite)”——是包含叶节点或其他组合对象等子项目的符合对象。 组合对象不知道其子项目所属的具体类, 它只通过通用的组件接口与其子项目交互。
  4. 客户端 (Client): 通过组件接口与所有项目交互。 因此, 客户端能以相同方式与树状结构中的简单或复杂对象进行交互。

首先定义一个组织的行为接口,这个接口大到总公司小到一个部门都得实现:

接口里提供两个方法,一个是打印出自己的组织结构的方法display()另外一个是展示组织职责的方法duty()

// 表示组织机构的接口
type Organization interface {
    display()
    duty()
}

定义和实现组合对象

type CompositeOrganization struct {
    orgName string
    depth   int
    list    []Organization
}

func NewCompositeOrganization(name string, depth int) *CompositeOrganization {
    return &CompositeOrganization{name, depth, []Organization{}}
}

func (c *CompositeOrganization) add(org Organization) {
    if c == nil {
        return
    }
    c.list = append(c.list, org)
}

func (c *CompositeOrganization) remove(org Organization) {
    if c == nil {
        return
    }
    for i, val := range c.list {
        if val == org {
            c.list = append(c.list[:i], c.list[i+1:]...)
            return
        }
    }
    return
}

func (c *CompositeOrganization) display() {
    if c == nil {
        return
    }
    fmt.Println(strings.Repeat("-", c.depth * 2), " ", c.orgName)
    for _, val := range c.list {
        val.display()
    }
}

func (c *CompositeOrganization) duty() {
    if c == nil {
        return
    }

    for _, val := range c.list {
        val.duty()
    }
}

组合对象用来表示有下属部门的组织,在代码里可以看到,它持有一个[]Organization类型的列表,这里存放的是它的下属组织。组合对象的displayduty这两个方法的实现完全就是把工作委托给他们的下属组织来做的,这也是组合模式的特点。

两个职能部门人力资源和财务部门的类型实现。

type HRDOrg struct {
    orgName string
    depth   int
}

func (o *HRDOrg) display() {
    if o == nil {
        return
    }
    fmt.Println(strings.Repeat("-", o.depth * 2), " ", o.orgName)
}

func (o *HRDOrg) duty() {
    if o == nil {
        return
    }
    fmt.Println(o.orgName, "员工招聘培训管理")
}

// Leaf对象--财务部门
type FinanceOrg struct {
    orgName string
    depth   int
}

func (f *FinanceOrg) display() {
    if f == nil {
        return
    }
    fmt.Println(strings.Repeat("-", f.depth * 2), " ", f.orgName)
}

func (f *FinanceOrg) duty() {
    if f == nil {
        return
    }
    fmt.Println(f.orgName, "员工招聘培训管理")
}

只要在客户端中组合好组织架构的结构,不管有几层组织,客户端对整个组织的调用是不会改变的。

func main() {
    root := NewCompositeOrganization("北京总公司", 1)
    root.add(&HRDOrg{orgName: "总公司人力资源部", depth: 2})
    root.add(&FinanceOrg{orgName: "总公司财务部", depth: 2})

    compSh := NewCompositeOrganization("上海分公司", 2)
    compSh.add(&HRDOrg{orgName: "上海分公司人力资源部", depth: 3})
    compSh.add(&FinanceOrg{orgName: "上海分公司财务部", depth: 3})
    root.add(compSh)

    compGd := NewCompositeOrganization("广东分公司", 2)
    compGd.add(&HRDOrg{orgName: "广东分公司人力资源部", depth: 3})
    compGd.add(&FinanceOrg{orgName: "南京办事处财务部", depth: 3})
    root.add(compGd)

    fmt.Println("公司组织架构:")
    root.display()

    fmt.Println("各组织的职责:")
    root.duty()
}

组合和装饰器的区别

组合模式和装饰器模式在结构上很像,拥有非常相似的类结构.

组合模式:为叶子对象和组合对象提供了统一的接口,叶子对象分担组合对象所有要做的工作。工作完成后向上层调用者返回

装饰器模式:被装饰对象完成核心工作,装饰器承担修饰工作。

组合模式的优点主要有以下两点

  1. 实现类似树形结构,可以清楚地定义各层次的复杂对象,表示对象的全部或部分层次。
  2. 简化了客户端代码,让客户端忽略了层次的差异,方便对整个层次结构进行控制。
    参考公众号网管叨bi叨
文章来源:https://blog.csdn.net/zhaicheng55/article/details/135377445
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。