1. 什么是策略模式?
策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。
核心思想是:当一个任务有多种处理方式(策略)时,将这些方式抽象成一个共同的接口,并为每种方式提供一个具体的实现类。环境(Context)角色持有一个策略接口的引用,从而能在运行时动态地切换和使用不同的策略。
与状态模式不同,策略模式的各种策略是独立的,客户端需要知道所有的策略,才能选择合适的策略。而状态模式的各种状态是相关的,客户端只需要知道当前状态,就可以根据状态转换规则自动切换到下一个状态。
2. 为什么需要策略模式?
在软件开发中,我们经常会遇到需要根据不同条件选择不同行为的场景。最直接的方法是使用 if-else 或 switch-case 结构。但当分支逻辑变得复杂,或者需要频繁增删新的分支时,这种方式会导致代码臃肿、难以维护,并且违反了“开闭原则”(对扩展开放,对修改关闭)。
策略模式正是为了解决这个问题而生。它有以下优点:
- 简化条件逻辑:将复杂的
if-else 链条替换为独立的策略类,使代码更清晰。
- 高扩展性:增加一个新的策略只需添加一个新的实现类,无需修改现有代码,符合开闭原则。
- 算法重用:策略可以被多个上下文共享。
- 运行时动态切换:可以在程序运行时根据需要更换算法策略。
3. 策略模式的实现(go)
让我们以一个数据压缩服务为例。该服务需要支持多种压缩算法,如 zip 和 gzip。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package compression
type Strategy interface { compress(data []byte) ([]byte, error) }
type zipStrategy struct{}
func (z *zipStrategy) compress(data []byte) ([]byte, error) { fmt.Println("Compressing data using ZIP") return append([]byte("zip_"), data...), nil }
type gzipStrategy struct{}
func (g *gzipStrategy) compress(data []byte) ([]byte, error) { fmt.Println("Compressing data using GZIP") return append([]byte("gzip_"), data...), nil }
type Compressor struct { S *Strategy }
func (c *Compressor) SetStrategy(strategy Strategy) { c.S = &strategy }
func (c *Compressor) CompressData(data []byte) ([]byte, error) { return c.S.compress(data) }
|
客户端可以根据需要创建和切换策略。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package main
import ( "fmt" "log" "compression" )
func main() { data := []byte("This is some data to be compressed.")
zip := &compression.zipStrategy{} compressor := &compression.Compressor{ S: zip, }
compressedData, err := compressor.CompressData(data) if err != nil { log.Fatal(err) } fmt.Printf("Compressed data: %s", compressedData)
gzip := &compression.gzipStrategy{} compressor.SetStrategy(gzip)
compressedData, err = compressor.CompressData(data) if err != nil { log.Fatal(err) } fmt.Printf("Compressed data: %s", compressedData) }
|
类图:
