手撸golang 结构型设计模式 组合模式
source link: https://segmentfault.com/a/1190000039162976
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
手撸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)
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK