手撸 golang 结构型设计模式 组合模式
缘起
最近温习设计模式
拜读谭勇德的 << 设计模式就该这样学 >>
本系列笔记拟采纳 golang 练习之
组合模式
组合模式(Composite Pattern)又叫作整体 - 局部(Part-Whole)模式,它的主旨是通过将单个对象(叶子节点)和组合对象(树枝节点)用雷同的接口进行示意,使得客户对单个对象和组合对象的应用具备一致性,属于结构型设计模式。
_
通明组合 vs 平安组合
- 通明组合: 叶子节点和树枝节点具备完全一致的接口
- 平安组合: 叶子节点和树枝节点从公共接口继承, 并做个性化扩大
场景
- 某线上学校, 提供系列 java 学习课程
- 提供某些简略课程, 如 ”java 根底 ”, 学员可一次性学完
- 提供某些组合课程, 外部蕴含了若干简略课程, 如 ”java 架构师 ” 课程, 外部蕴含 ”java 根底 ”, “java 高级编程 ” 等多门课程, 须要分步顺次学习, 能力实现
- 为不便业务层调用, 依据 平安组合模式, 简略课程和组合课程均实现公共接口的 Learn 办法.
设计
- IUser: 定义学员用户接口
- ICourse: 定义课程的公共接口
- ICompositeCourse: 组合课程的个性化接口, 从 ICourse 继承, 并增加了 Append(子课程)的办法
- tMockUser: 虚构学员的实现类
- tSimpleCourse: 简略课程的实现类, 实现 ICourse 接口
- tCompositeCourse: 组合课程的实现类, 继承 tSimpleCourse, 并实现了 ICompositeCourse 接口
单元测试
composite_pattern_test.go
package structural_patterns
import (
"learning/gooop/structural_patterns/composite"
"testing"
)
func Test_CompositePattern(t *testing.T) {user := composite.NewMockUser(1, "张三")
sc := composite.NewSimpleCourse(11, "Java 根底", 100)
user.Learn(sc)
user = composite.NewMockUser(2, "李四")
cc := composite.NewCompositeCourse(21, "Java 架构师", 500)
cc.Append(composite.NewSimpleCourse(11, "Java 根底", 100))
cc.Append(composite.NewSimpleCourse(12, "Java 高级编程", 100))
cc.Append(composite.NewSimpleCourse(13, "设计模式", 100))
cc.Append(composite.NewSimpleCourse(14, "Spring 技术底细", 100))
cc.Append(composite.NewSimpleCourse(15, "SpringCloud 架构指南", 100))
user.Learn(cc)
}
测试输入
$ go test -v composite_pattern_test.go
=== RUN Test_CompositePattern
张三 is learning Java 根底
李四 is learning Java 架构师.Java 根底
李四 is learning Java 架构师.Java 高级编程
李四 is learning Java 架构师. 设计模式
李四 is learning Java 架构师.Spring 技术底细
李四 is learning Java 架构师.SpringCloud 架构指南
--- PASS: Test_CompositePattern (0.00s)
PASS
ok command-line-arguments 0.005s
IUser.go
定义学员用户接口
package composite
type IUser interface {ID() int
Name() string
Learn(course ICourse)
}
ICourse.go
定义课程的公共接口
package composite
type ICourse interface {ID() int
Name() string
Price() float64
SetUser(user IUser)
Learn() LearningStates}
type LearningStates int
const MORE LearningStates = 1
const DONE LearningStates = 2
ICompositeCourse.go
组合课程的个性化接口, 从 ICourse 继承, 并增加了 Append(子课程)的办法
package composite
type ICompositeCourse interface {
ICourse
Append(course ICourse)
}
tMockUser.go
虚构学员的实现类
package composite
type tMockUser struct {
iID int
sName string
}
func NewMockUser(id int, name string) IUser {
return &tMockUser{id, name,}
}
func (me *tMockUser) ID() int {return me.iID}
func (me *tMockUser) Name() string {return me.sName}
func (me *tMockUser) Learn(course ICourse) {course.SetUser(me)
for {state := course.Learn()
if state == DONE {break}
}
}
tSimpleCourse.go
简略课程的实现类, 实现 ICourse 接口
package composite
import "fmt"
type tSimpleCourse struct {
iID int
sName string
fPrice float64
mUser IUser
}
func NewSimpleCourse(id int, name string, price float64) ICourse {
return &tSimpleCourse{id, name, price, nil,}
}
func (me *tSimpleCourse) ID() int {return me.iID}
func (me *tSimpleCourse) Name() string {return me.sName}
func (me *tSimpleCourse) Price() float64 {return me.fPrice}
func (me *tSimpleCourse) SetUser(user IUser) {me.mUser = user}
func (me *tSimpleCourse) Learn() LearningStates {fmt.Printf("%s is learning %s\n", me.mUser.Name(), me.sName)
return DONE
}
tCompositeCourse.go
组合课程的实现类, 继承 tSimpleCourse, 并实现了 ICompositeCourse 接口
package composite
import "fmt"
type tCompositeCourse struct {
tSimpleCourse
mCourseList []ICourse
iCourseIndex int
}
func NewCompositeCourse(id int, name string, price float64) ICompositeCourse {
return &tCompositeCourse {
tSimpleCourse: tSimpleCourse{id, name, price, nil,},
mCourseList: make([]ICourse, 0),
iCourseIndex: 0,
}
}
func (me *tCompositeCourse) Append(course ICourse) {me.mCourseList = append(me.mCourseList, course)
}
func (me *tCompositeCourse) Learn() LearningStates {if me.IsDone() {fmt.Printf("%s is learning %s: no more courses\n", me.mUser.Name(), me.Name())
return DONE
}
course := me.mCourseList[me.iCourseIndex]
fmt.Printf("%s is learning %s.%s\n", me.mUser.Name(), me.Name(), course.Name())
me.iCourseIndex++
if me.IsDone() {return DONE} else {return MORE}
}
func (me *tCompositeCourse) IsDone() bool {return me.iCourseIndex >= len(me.mCourseList)
}
组合模式小结
组合模式的长处
(1)分明地定义各层次的简单对象,示意对象的全副或局部档次。
(2)让客户端疏忽了档次的差别,不便对整个层次结构进行管制。
(3)简化客户端代码。
(4)合乎开闭准则。
组合模式的毛病
(1)限度类型时会较为简单。
(2)使设计变得更加形象。
(end)