手撸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_patternsimport (    "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)PASSok      command-line-arguments  0.005s

IUser.go

定义学员用户接口

package compositetype IUser interface {    ID() int    Name() string    Learn(course ICourse)}

ICourse.go

定义课程的公共接口

package compositetype ICourse interface {    ID() int    Name() string    Price() float64    SetUser(user IUser)    Learn() LearningStates}type LearningStates intconst MORE LearningStates = 1const DONE LearningStates = 2

ICompositeCourse.go

组合课程的个性化接口, 从ICourse继承, 并增加了Append(子课程)的办法

package compositetype ICompositeCourse interface {    ICourse    Append(course ICourse)}

tMockUser.go

虚构学员的实现类

package compositetype 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 compositeimport "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 compositeimport "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)