Go语言精进之路-白明 | 变长参数函数的妙用
All

Go语言精进之路-白明 | 变长参数函数的妙用

MrSnake
2022-03-14 / 4 评论 / 227 阅读 / 正在检测是否收录...

实现功能选项模式

在日常Go编程中,我们经常会实现一些带有设置选项的创建型函数。对于一些复杂的Go包中的创建型函数,它要提供的可设置选项有时多达数十种,甚至后续还会增加。那么在选项增长的同时,依旧保持对外接口的稳定性,就成了关键。
例:实现一个NewFinishedHouse函数,其中选项有:

  • 装修风格
  • 是否是中央空调
  • 地面材料
  • 墙面材料
    还有可能会增加的选项。

版本1实现:使用结构体封装配置选项

type FinishedHouse struct {
    style     string
    isCentral bool
    floor     string
    wall    string
}
type Option struct {
    Style     string
    IsCentral bool
    Floor     string
    Wall    string
}

func NewFinishedHouse(option *Option) *FinishedHouse {
    var (
        style = "fashion"
        isCentral = true
        floor = "normal"
        wall = "standard"
    )
    if option != nil {
        style = option.Style
        isCentral = option.IsCentral
        floor = option.Floor
        wall = option.Wall
    }
    return &FinishedHouse{
        style: style,
        isCentral: isCentral,
        floor: floor,
        wall: wall,
    }
}

采用这种方式的好处是,当选项增加时,只需增加结构体option的字段,原本的函数签名是不变的。

版本2实现:使用功能选项模式

Go语言之父Rob Pike早在2014年就在其博文“自引用函数与选项设计”[2]中论述了一种被后人称为“功能选项”(functional option)的模式,这种模式应该是目前进行功能选项设计的最佳实践。

type FinishedHouse struct {
    style     string
    isCentral bool
    floor     string
    wall    string
}

type Option func(*FinishedHouse)

func NewFinishedHouse(options ...Option) *FinishedHouse {
    h := &FinishedHouse{
        style: "fashion",
        isCentral: true,
        floor: "normal",
        wall: "standard",
    }
    for _, option := range options {
        option(h)
    }
    return h
}

func WithStyle(style string) Option {
    return func(f *FinishedHouse) {
        f.style = style
    }
}

func WithIsCentral(isCentral bool) Option {
    return func(f *FinishedHouse) {
        f.isCentral = isCentral
    }
}

func WithFloor(floor string) Option {
    return func(f *FinishedHouse) {
        f.floor = floor
    }
}

func WithWall(wall string) Option {
    return func(f *FinishedHouse) {
        f.wall = wall
    }
}

func main() {
   fmt.Printf("%+v", NewFinishedHouse()) // 默认选项
   fmt.Printf("%+v", NewFinishedHouse(
       WithStyle("classic"),
       WithIsCentral(false),
   ))
}

我们看到在该方案中,FinishedHouse的配置选项不是通过存储在结构体中的配置参数传入的,而是通过对FinishedHouse值本身进行操作的函数调用(利用函数的“一等公民”特质)实现的,并且通过使用变长参数函数,我们可以随意扩展传入的配置选项的个数。

0

评论 (4)

取消
  1. 头像
    1
    Windows 10 · Google Chrome

    555

    回复
  2. 头像
    1
    Windows 10 · Google Chrome

    画图

    回复
  3. 头像
    1
    Windows 10 · Google Chrome

    555

    回复
  4. 头像
    程明
    Windows 10 · Google Chrome

    亲爱的朋友:您好!中国各地出现了新冠变种毒株JN.1,传播速度比原来的XBB变种加快七到八倍,对免疫逃脱能力也进一步加强,最新的疫苗对它没有保护力,各地死亡人数在持续攀升,很多病患突然猝死。古今中外的预言也说了这几年人类有大灾难,如刘伯温在预言中说 "贫者一万留一千,富者一万留二三”,“贫富若不回心转,看看死期到眼前”, 预言中也告诉世人如何逃离劫难的方法,真心希望您能躲过末劫中的劫难,有个美好的未来,请您务必打开下方网址认真了解,内有躲避瘟疫保平安的方法。网址1:https://d14j9nji5l5p80.cloudfront.net/24gj 网址2:bitly.net/p555p 网址3:https://github.com/19920513/www/blob/master/README.md?lsnms

    回复