[项目与实践] go 设计模式

背景

之前看过用go实现的23种常见的设计模式,但是有些模式总感觉很别扭,像是为了实现而实现。
此外,go也不是个强面向对象语言,有些依赖于继承的设计模式用go实现起来就更加怪异了。难道go就没有“方言化”的设计模式吗? :yinxian:
非也,库用多了,你会发现很多源码里面也用到了设计模式,而且非常优雅,像是很多需要New一个client的源码就会用到Options模式, 而像gorm库,用到的链式查询,是用了builder模式,还有gin中的中间件,用到了责任链模式...

果然阅读源码是快速进步的必经之路呀 :tushe:

options 模式

大家知道,go没有构造函数这么一说,所以返回一个实例完全靠通过传入的形参来初始化结构体的字段,但是假如结构体字段一多起来,函数要传入的形参长到换三行都放不下,更别提有时候就传一两个,要是排列组合起来,1000行代码900行New :pen: :pen:

type Student struct {
    Name        string
    Class       int
    Number      int
    TeacherName string
    Address     string
    Age         int
}

func NewStudentClassInfo(class int, teacher string) *Student {
    return &Student{
        TeacherName: teacher,
        Class:       class,
    }
}

func NewStudentInfo(address string, name string, number int, age int) *Student {
    return &Student{
        Name:    name,
        Address: address,
        Number:  number,
        Age:     age,
    }
}

//....

so, 这时候就需要安利你 Functional Options 模式了 :ku:

func main() {

    s := NewStudent(
        WithClass(1),
        WithName("yezi"),
    )

    fmt.Println(s)
}

type Student struct {
    Name        string
    Class       int
    Number      int
    TeacherName string
    Address     string
    Age         int
}

type OptionFun func(s *Student)

func NewStudent(opt ...OptionFun) *Student {
    student := &Student{
        Name:  "undefined",
        Class: 1,
    }

    for _, o := range opt {
        o(student)
    }

    return student
}

// 每个参数的设置使用一个闭包函数完成,2^n - 1 -> n

func WithName(name string) OptionFun {
    // 采用闭包的方式设置
    return func(s *Student) {
        s.Name = name
    }
}

func WithClass(class int) OptionFun {
    return func(s *Student) {
        s.Class = class
    }
}

本质就是让每一个配置项的设置都独立成为一个函数,而且是可变式的,在New函数中先赋默认值,然后通过遍历执行可变参数函数来设置对应的字段值即可

  • 个数无关
  • 参数位置无关
  • 解耦

另一种写法(源码中常见的,继续封装了一层并抽象化)


type Student struct {
    Name        string
    Class       int
    Number      int
    TeacherName string
    Address     string
    Age         int
}

type Option interface {
    Apply(s *Student)
}

type OptionFun func(s *Student)

func (f OptionFun) Apply(s *Student) {
    f(s)
}

func NewStudent(opt ...Option) *Student {
    student := &Student{
        Name:  "undefined",
        Class: 1,
    }

    for _, o := range opt {
        o.Apply(student)
    }

    return student
}

// 每个参数的设置使用一个闭包函数完成,2^n - 1 -> n

func WithName(name string) OptionFun {
    // 采用闭包的方式设置
    return OptionFun(func(s *Student) {
        s.Name = name
    })
}

func WithClass(class int) OptionFun {
    return OptionFun(func(s *Student) {
        s.Class = class
    })
}

参考链接

Golang 中的 Functional Options 模式和 Builder 模式

一些实用的编程模式 | Options模式

点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注