设计模式_Options模式

Options模式

推荐阅读大佬原文一些实用的 Go 编程模式 | Options模式

此记录仅做个人笔记,设计模式适用于各个语言

一、Options模式解决什么问题

Options模式可以让具有多个可选参数的函数或方法更整洁和好扩展,当一个函数具有6个以上的可选参数使用这种模式有很明显的优化体验。

二、多参数函数传值解决方案

对需要多个参数的函数传参方式有以下几种解决方式:

  • 传入固定参数值
  • 传入配置对象
  • 传入可变参数
  • 使用options模式

2.1 传入固定参数值

type Person struct{
	Id string
	Name string
	Position string
}

type Company struct {
	Name string
}

//
// Dimission
//  @Description: 员工离职处理
//  @param dP 离职员工
//  @param mP 主管
//  @param tP 接手人
//  @param company 公司
//  @param wData 工作资料
//  @param dFile 离职文件
//  @param wList 交接清单
//  @param dTime 离职时间
//  @return proof 离职证明
//
func Dimission(dP, mP,tP Person,company Company, wData []byte, dFile []byte, wList map[string]string, dTime time.Time) (proof []byte) {
	// 第一步就是检查各个参数是否有效,某些参数无效时填入默认值,例如离职时间
	if wData !=nil {
		// ...
	}
	if dFile !=nil {
		// ...
	}

	if wList != nil {
		// ...
	}
	return nil
}

优点:简单直接

缺点:

  • 函数逻辑中必须全部参数的判空逻辑等无关代码

  • 对于用户不需要自定义的值,也需要调用者传入零值

    python中有默认值来解决

    java中可以通过重载来解决

    go中需要通过重新声明新的方法,然后再新方法中自动设置旧方法的默认值,来进行解决

2.2 传入配置对象 (常用)

type DimissionJob struct {
	DP Person
	MP Person
	TP Person
	Company
	WData []byte
	DFile []byte
	WList []byte
	DTime time.Time
}
func DimissionWithStruct(dj *DimissionJob) (proof []byte) {
	// 检查各个参数
	return nil
}

优点:代码简洁,面向对象

缺点:线程不安全

go中是值传递的,为了避免复制参数,提高性能,这里参数接收的是指针,有可能在函数内部进行时,对象在外部被更改。

日常使用时,传递都是对象的func DimissionWithStruct(dj DimissionJob),工作中常常这么写

2.3 传入可变参数

func DimissionWithVariable(dP Person, opts ...interface{}) (proof []byte) {
	// 检查各个参数
	return nil
}

优点:参数可变

缺点:需要按设置好顺序传参,否则无法正确变化

2.4 使用options模式

type DimissionOption struct {
	DP Person
	MP Person
	TP Person
	Company
	WData []byte
	DFile []byte
	WList []byte
	DTime time.Time
}

type Option struct {
	apply func(option *DimissionOption)
}

func defaultDimissionOptions() *DimissionOption {
	return &DimissionOption{
		// 默认请求选项
		// ....
	}
}

func WithWData(d []byte) *Option {
	return &Option{
		apply: func(option *DimissionOption) {
			option.WData = d
		},
	}
}

func WithDFile(d []byte) *Option {
	return &Option{
		apply: func(option *DimissionOption) {
			option.DFile = d
		},
	}
}

func WithDTime(d time.Time) *Option {
	return &Option{
		apply: func(option *DimissionOption) {
			option.DTime = d
		},
	}
}

func DimissionWithVariable(dP, mP,tP Person,company Company, options ...*Option) (proof []byte) {
	reqOpts := defaultDimissionOptions() // 默认的请求选项
	for _, opt := range options {      // 在reqOpts上应用通过options设置的选项
		opt.apply(reqOpts)
	}

	// 进行业务操作

	return nil
}

func Test() {
	dP := Person{Name: "职员A"}
	mP := Person{Name: "主管B"}
	tP := Person{Name: "职员C"}
	c := Company{Name: "XXXX科技公司"}

	wData := []byte("工作资料")
	dFile := []byte("交接资料")
	dTime, err := time.Parse("2002-01-02", "2021-10-27")
	if err != nil {
		log.Fatal(err.Error())
		return
	}
    
    // 使用
	DimissionWithVariable(dP, mP,tP, c, WithWData(wData))
	DimissionWithVariable(dP, mP,tP, c, WithWData(wData), WithDFile(dFile), WithDTime(dTime))
}

如果后面要给配置对象里增加其他配置项,只需要扩充类型的字段,在定义一个对应的With方法即可,扩展性完全在可接受范围内。

个人总结:

没有最好的解决方案,在选择方案时需要在项目开发与项目拓展两端进行权重,然后选择适合的解决方案。这里的options模式在rpc框架得到了广泛的使用,说明了options模式也是成熟的解决方式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值