设计模式-组合模式

组合模式(Composite Pattern):将对象组合成树形结构表示来“部分-整体”的层次结构,使用户对单个对象和组合对象的使用具有一致性。

看上去有点抽象,其实就是一种树形结构。比如二叉树,每个非叶子节点都有2个子节点,叶子节点除了没有子节点外和父节点、根节点都是一样的。在通俗来说,比如公司的层级架构,从老板(根节点)到经理(非叶子节点)再到员工(叶子节点),他们有很多共性的东西,比如都有姓名、工号,老板和经理有添加、移除手下员工的能力,而作为员工则只能干活。

从代码实现来说,就是老板、经理、员工使用一个抽象类,而老板和经理实现某些特定的方法,这就是组合模式,十分容易理解。

composite.png

package main

import (
	"fmt"
)

type duty interface {
	addStaff(d duty)
	getStaff() []duty
	printUserInfo()
	printEmployeesInfo()
}

type Staff struct {
	number   string
	name     string
	position string
}

func (s *Staff) printUserInfo() {
	fmt.Printf("ID:%s,Name:%s,position:%s\n", s.number, s.name, s.position)
}
func (s *Staff) printEmployeesInfo() {
	return
}
func (s *Staff) addStaff(d duty) {
	return
}
func (s *Staff) getStaff() []duty {
	return []duty{}
}

type Manager struct {
	self Staff
	arr  []duty
}

func (m *Manager) getStaff() []duty {
	return m.arr
}
func (m *Manager) addStaff(d duty) {
	m.arr = append(m.arr, d)
}
func (m *Manager) printUserInfo() {
	m.self.printUserInfo()
}
func (m *Manager) printEmployeesInfo() {
	for _, e := range m.arr {
		e.printUserInfo()
		for _, ee := range e.getStaff() {
			ee.printUserInfo()
			ee.printEmployeesInfo()
		}
	}
}

type Employees struct {
	self Staff
}

func (e *Employees) addStaff(d duty) {
	return
}
func (e *Employees) getStaff() []duty {
	return []duty{}
}
func (e *Employees) printUserInfo() {
	e.self.printUserInfo()
}
func (e *Employees) printEmployeesInfo() {
	return
}

func main() {
	ceo := Manager{self: Staff{name: "ceo", number: "001", position: "CEO"}}
	techM := Manager{self: Staff{name: "技术经理", number: "002", position: "技术经理"}}
	techMG1 := Manager{self: Staff{name: "技术组长1", number: "004", position: "技术组长"}}
	techMG2 := Manager{self: Staff{name: "技术组长2", number: "005", position: "技术组长"}}
	finaM := Manager{self: Staff{name: "财务经理", number: "003", position: "财务经理"}}
	emp1 := Employees{self: Staff{name: "开发1", number: "0041", position: "开发人员"}}
	emp2 := Employees{self: Staff{name: "开发2", number: "0052", position: "开发人员"}}
	emp3 := Employees{self: Staff{name: "财务1", number: "0031", position: "财务人员"}}

	ceo.addStaff(&techM)
	ceo.addStaff(&finaM)

	techM.addStaff(&techMG1)
	techM.addStaff(&techMG2)

	techMG1.addStaff(&emp1)
	techMG2.addStaff(&emp2)
	finaM.addStaff(&emp3)

	ceo.printUserInfo()
	ceo.printEmployeesInfo()
}

程序输出如下:

ID:001,Name:ceo,position:CEO
ID:002,Name:技术经理,position:技术经理
ID:004,Name:技术组长1,position:技术组长
ID:0041,Name:开发1,position:开发人员
ID:005,Name:技术组长2,position:技术组长
ID:0052,Name:开发2,position:开发人员
ID:003,Name:财务经理,position:财务经理
ID:0031,Name:财务1,position:财务人员

如果不使用组合模式,代码则需要建立一个Manager类,里面有添加、展示员工方法,再建立一个Employees类表示员工,这个类仅有printUserInfo方法。而使用组合模式,则将这2者统一为Staff类的子类实现相关接口即可,这也是面向抽象编程的思想。

应用场景

  1. 表示对象的“部分-整体”层次结构时。
  2. 希望用户忽略组合对象和单个对象的不同时。