使用选项模式设置Go语言函数的默认参数

Go语言使用选项模式设置函数的默认参数

Python与Go使用默认参数对比

在使用Go语言写函数时,不能像Python一样设置函数的默认参数,有时候,不能设置默认参数让我们处理起来有点麻烦,特别是有时候函数的参数想让使用者自己决定的时候,不禁让人感叹Python的方便。
比如,我们实现一个对象——点奶茶:
在这里插入图片描述

使用Python实现

class Tea:
    
    def __init__(self , name , heat=False , sugar = 5):
        self.name = name
        self.heat = heat
        self.sugar = sugar
        
    def get_tea(self):
        print("name:{}, heat:{}, sugar:{},".format(self.name , self.heat ,self.sugar))

t = Tea("hahahha")
t.get_tea()    
 
t = Tea("tea2",True,3)
t.get_tea()     

使用Go语言实现

package main

import (
	"fmt"
)
// 定义默认参数的常量
const (
	defaultHeat  = false
	defaultSugar = 5
)

type Tea struct {
	name  string
	heat  bool
	sugar int
}

// 默认参数的选项,中间对象
type TeaOptions struct {
	heat  bool
	sugar int
}

// 创建默认参数对象
func NewDaulft() *TeaOptions{
	return &TeaOptions{
		heat : defaultHeat,
		sugar: defaultSugar,
	}
}

// 创建具体对象
func NewTea(name string , ops *TeaOptions)( *Tea,error){
	return &Tea{
		name: name,
		heat: ops.heat,
		sugar: ops.sugar,
	},nil
}

func (t Tea) getTea() {
	fmt.Printf("name:%s , heat:%t , sugar:%d\n", t.name, t.heat, t.sugar)
}

func main() {

	// 使用默认参数
	tea1, _ := NewTea("tea1", NewDaulft())
	tea1.getTea()
	// 不使用默认参数,创建TeaOptions对象传参
	tea2, _ := NewTea("tea2", &TeaOptions{heat: true, sugar: 10})
	tea2.getTea()
}

从上面可以看到,Go语言实现函数默认方式比较麻烦,而且,每次创建对象时都需要再创建一个中间对象——TeaOptions负责有默认参数的部分,操作起来很麻烦,并且发生变化就得修改很多处地方。

Go使用选项模式设置默认参数

为了解决这个麻烦,便于扩展,可以使用设计模式中的选项模式来创建对象。代码如下:

package main

import (
	"fmt"
)

// 定义默认的常量
const (
	defaultHeat  = false
	defaultSugar = 5
)

type Tea struct {
	name  string
	heat  bool
	sugar int
}
// 在原有的基础上修改
// 默认参数的选项
type options struct {
	heat  bool
	sugar int
}

// 接口类型,apply方法
type OptionContainer interface {
	apply(*options)
}

// 函数类型,实现了apply方法 -- OptionContainer
type optionFunc func(*options)

func (f optionFunc) apply(o *options) {
	f(o)
}

// 设置heat参数
func WithHeat(h bool) OptionContainer {
	return optionFunc(func(o *options) { //optionFunc()为类型转换
		o.heat = h
	})
}

func WithSugar(s int) OptionContainer {
	return optionFunc(func(o *options) { //optionFunc()为类型转换
		o.sugar = s
	})
}

func NewTea(name string, ops ...OptionContainer) (*Tea, error) {
	// 填充默认值
	opt := options{
		heat:  defaultHeat,
		sugar: defaultSugar,
	}

	// 遍历可变参数,完成值的填充
	for _, o := range ops {
		o.apply(&opt)
	}

	return &Tea{
		name:  name,
		heat:  opt.heat,
		sugar: opt.sugar,
	}, nil
}

func (t Tea) getTea() {
	fmt.Printf("name:%s , heat:%t , sugar:%d分\n", t.name, t.heat, t.sugar)
}

func main() {
	// 使用默认参数
	tea1, _ := NewTea("tea1")
	tea1.getTea()
	// 不使用默认参数
	h2 := WithHeat(true)
	tea2, _ := NewTea("tea2", h2, WithSugar(1))
	tea2.getTea()
}

上面代码实现默认参数支持就比较贴切,只需要在创建的函数参数中设置好参数,不然就使用默认参数。当然,相应的,增加了许多代码,看起来更加复杂。不过,这些都是为了方便扩展。


总结

使用Go语言实现函数默认参数比较麻烦,可以采用中间对象的方法设置默认参数,或者使用选项模式传入一个能自己填充值的选项参数完成默认参数的设置。后者相对来说代码量会增多,更加复杂。但是,也带来了很多优点:

  • 没有参数数量和顺序的限制,方便后续扩展。
  • 在参数发生变化时保持兼容性
  • 参数较多的情况下,可以选择性设置

注意,参数较少时就不要采用选项模式。


参考
项目参考:https://github.com/marmotedu
(@colin)

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值