概念

策略模式是一种行为设计模式, 它将一组行为转换为对象, 并使其在原始上下文对象内部能够相互替换。

策略模式主要的作用还是解耦策略的定义、创建和使用,控制代码的复杂度,让每个部分都不至于过于复杂、代码量过多。

除此之外,对于复杂代码来说,策略模式还能让其满足开闭原则,添加新策略的时候,最小化、集中化代码改动,减少引入 bug 的风险。

应用场景

1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。

2、一个系统需要动态地在几种算法中选择一种。

3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

优点

  • 算法可自由切换
  • 避免多重条件判断
  • 扩展性好

缺点

  • 策略类会增多
  • 所有策略类都需要对外暴露

代码实现

strategy.go

package strategy

type Strategy interface {
	DoOperation(num1, num2 int) int
}

// 加法
type OperationAdd struct{}

func NewOperationAdd() *OperationAdd {
	return &OperationAdd{}
}

func (*OperationAdd) DoOperation(num1, num2 int) int {
	return num1 + num2
}

// 减法
type OperationSubtract struct{}

func NewOperationSubtract() *OperationSubtract {
	return &OperationSubtract{}
}

func (*OperationSubtract) DoOperation(num1, num2 int) int {
	return num1 - num2
}

// 乘法
type OperationMultiply struct{}

func NewOperationMultiply() *OperationMultiply {
	return &OperationMultiply{}
}

func (*OperationMultiply) DoOperation(num1, num2 int) int {
	return num1 * num2
}

context.go

package strategy

type Context struct {
	strategy Strategy
}

func NewContext(str Strategy) *Context {
	return &Context{
		strategy: str,
	}
}

func (ctx *Context) SetStrategy(strategy Strategy) {
	ctx.strategy = strategy
}

func (ctx *Context) ExecuteStrategy(num1, num2 int) int {
	if ctx.strategy == nil {
		return 0
	}
	return ctx.strategy.DoOperation(num1, num2)
}

代码测试

func TestStrategy(t *testing.T) {
	context := NewContext(NewOperationAdd())
	fmt.Println("11 + 6 = ", context.ExecuteStrategy(11, 6))

	context = NewContext(NewOperationSubtract())
	fmt.Println("18 - 3 = ", context.ExecuteStrategy(18, 3))

	context = NewContext(NewOperationMultiply())
	fmt.Println("11 * 9 = ", context.ExecuteStrategy(11, 9))
}

测试结果

=== RUN   TestStrategy
11 + 6 =  17
18 - 3 =  15
11 * 9 =  99
--- PASS: TestStrategy (0.00s)
PASS
ok      ginstudy/strategy       0.003s