今天介绍一个常见的设计模式-策略模式,并基于一个简单的例子来讲解。

策略模式介绍

策略模式(Strategy Pattern)是一种行为型设计模式,它将一组算法封装成独立的对象,并使它们可以互相替换。这样做的好处是,可以在运行时动态地改变对象的行为,而不需要修改使用该对象的代码。

何时可以使用策略模式呢

我们在用GO编程的时候经常碰到多层控制语句,一层又一层,既不优雅,也不利于后续维护。比如下述这种:

1
2
3
4
5
6
7
8
if xxx {
// do something
} else if xxx {
// do something
} else if xxx {
// do something
 else {
}

虽然按这种模式写起来简单快捷,但它也违背了面向对象的两个原则:

  • 单一职责原则:多个控制语句,意味着拥有多种功能;
  • 开闭原则:当要进行修改时,原有代码不可避免要被修改;

此时就可以采用策略模式来替换这类多层控制语句。

go 实现策略模式

go 语言该怎么实现策略模式呢?

在Go语言中,策略模式可以通过接口和函数来实现。首先,我们定义一个接口,该接口声明了算法执行的方法。然后,我们可以为每个具体的算法实现一个结构体,并实现接口中的方法。最后,我们可以在需要使用算法的地方,通过接口来调用具体的算法。

下面通过一个简单的例子来讲解策略模式, 现在有这样一个场景我们现在有2个数据表,这2个数据表拥有相同的字段,都可以根据 name 来查询某个数据,我们需要根据参数的不同来决定使用哪种表进行查询, 在没有使用策略模式时, 我们往往使用大量的if来实现这个操作。 接下来由我来介绍策略模式来实现相同的操作。

先定义查询操作的接口:

1
2
3
type DataStrategy interface {
	Query(name string)
}

定义2张表的查询struct,并实现DataStrategy接口:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

// table1 通过table1 来查询
type table1 struct{}

func (s *table1) Query(name string) {
	fmt.Println("table1 query")
}

// table2
type table2 struct{}

func (s *table2) Query(name string) {
	fmt.Println("table2 query")
}

再定义 Data 对象用来执行不同的策略:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
type Data struct {
	impl DataStrategy
}

func (r *Data) SetTable(i DataStrategy) {
	r.impl = i
}

func (r *Data) Query(name string) {
	r.impl.Query(name)
}

运行代码:

1
2
table1 query
table2 query

小结

策略模式是一种非常有用的设计模式,它可以在不修改现有代码的情况下,动态地改变算法或行为。在Go语言中,我们可以通过接口和函数来实现策略模式。通过合理地应用策略模式,我们可以使代码更加灵活、可扩展,并提高代码的可维护性。