Opts Pattern

Opts Pattern

通常情况下,创建一个新的对象会使用默认构造器。

假设现在我们要准备一个家庭医药包,里面有抵抗新冠的一些常用药,比如莲花清瘟,999感冒灵颗粒,藿香正气片 etc.

package main

import "fmt"

// MedicalKit contains medicine that helps alleviate symptoms of COVID-19 virus
type MedicalKit struct {
	// 莲花清瘟
	LianHuaQingWenCapsule int

	// 999
	GanMaoLingKeLi int

	// 藿香正气片
	LophanthusAntiFebrileTablet int
}

// NewMedicalKit create a new default medical kit
func NewMedicalKit() *MedicalKit{
	return &MedicalKit{
		LianHuaQingWenCapsule: 1,
		GanMaoLingKeLi: 1,
		LophanthusAntiFebrileTablet: 1,
	}
}

func main() {
	kit:=NewMedicalKit()

	fmt.Println(kit)
}

那现在如果要创建的同时,修改对象的状态,怎么办?

你会很容易想到带参构造器:

// NewMedicalKit create a new default medical kit
func NewMedicalKit(LianHuaQingWenCapsule int,LophanthusAntiFebrileTablet int,GanMaoLingKeLi int,) *MedicalKit{

	return &MedicalKit{
		LianHuaQingWenCapsule: LianHuaQingWenCapsule,
		GanMaoLingKeLi: GanMaoLingKeLi,
		LophanthusAntiFebrileTablet: LophanthusAntiFebrileTablet,
	}
}

但是这样有一个问题,如果我只想传入其中一个参数,保持其他为默认值,在调用的时候,我不得不将参数全部传入。

kit:=NewMedicalKit(1,2,3)

另外一个问题是我需要记住参数传入的顺序,否则就会有差错。

那有没有一种方法,让我可以实现不需要关心参数传入顺序且不用传入非必要参数呢?答案是Opts模式

Opts模式

Opts模式相比默认构造器有如下优势

  • 封装内部对象如何更改状态自身
  • 只需要向构造器传入想修改的参数,默认的不需要传
  • 不需要去关心向构造器传入的参数的顺序
package main

import "fmt"

// MedicalKit contains medicine that helps alleviate symptoms of COVID-19 virus
type MedicalKit struct {
	// 莲花清瘟
	LianHuaQingWenCapsule int

	// 999
	GanMaoLingKeLi int

	// 藿香正气片
	LophanthusAntiFebrileTablet int
}


var (
	DefaultLianHuaQingWenCapsuleCount =1
	DefaultGanMaoLingKeLiCount=1
	DefaultLophanthusAntiFebrileTabletCount=1
)
// MedicalKitOptions 可以更改构造器行为
type MedicalKitOptions func(*MedicalKit)

func NewMedicalKit(opts  ...MedicalKitOptions) *MedicalKit{
	kit:=&MedicalKit{
		LophanthusAntiFebrileTablet: DefaultLophanthusAntiFebrileTabletCount,
		GanMaoLingKeLi: DefaultGanMaoLingKeLiCount,
		LianHuaQingWenCapsule: DefaultLianHuaQingWenCapsuleCount,
	}
    // 执行每个option函数
	for _, opt :=range opts{
		opt(kit)
	}
	return kit
}


func main() {
	with999:= func(count int) MedicalKitOptions{
		return func(k *MedicalKit){
			k.GanMaoLingKeLi=count
		}
	}
	withLianHua:= func(count int) MedicalKitOptions{
		return func(k *MedicalKit) {
			k.LianHuaQingWenCapsule=count
		}
	}

	// without need to pass all arguments
	kit:=NewMedicalKit(with999(2),withLianHua(3))
	fmt.Println(kit)

}

posted @ 2022-12-09 16:53  Oneslide  阅读(38)  评论(0编辑  收藏  举报