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

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

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

composite.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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()
}

程序输出如下:

1
2
3
4
5
6
7
8
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. 希望用户忽略组合对象和单个对象的不同时。