【Go-设计模式】策略模式 详解

shadowLogo

概念:

定义一系列算法,让这些算法在运行时可以互换,使得分离算法,符合开闭原则。

定义 算法族(策略组),分别封装起来,让它们之间可以 互相替换,此模式让 算法的变化 独立于 使用算法的Client

这算法体现了几个设计原则:

  • (1)把 变化的代码不变的代码 中分离出来;
  • (2)针对 接口编程,而不是 具体类
  • (3)多用 组合/聚合,少用 继承(Client通过 组合方式 使用策略)

军师


UML:

uml

  • Context
    环境,持有一个 Strategy的引用
  • Strategy
    抽象策略,定义 策略的具体功能实现
  • ConcreteStrategy
    具体策略实现抽象策略 约定的 相关算法具体实现

示例:

抽象的策略接口:

策略接口1:

type Strategy1 interface {
	OperationA()
}

策略接口2:

type Strategy2 interface {
	OperationB()
	OperationC()
}

具体的策略实现类:

策略实现类1:

type ConcreteStrategyI struct {
}

func (this ConcreteStrategyI) OperationA() {
	fmt.Println("策略1 实现的 OperationA")
}

策略实现类2:

type ConcreteStrategyII struct {
}

func (this ConcreteStrategyII) OperationA() {
	fmt.Println("策略2 实现的 OperationA")
}

策略实现类3:

type ConcreteStrategyIII struct {
}

func (this ConcreteStrategyIII) OperationB() {
	fmt.Println("策略3 实现的 OperationB")
}

func (this ConcreteStrategyIII) OperationC() {
	fmt.Println("策略3 实现的 OperationC")
}

策略实现类4:

type ConcreteStrategyIV struct {
}

func (this ConcreteStrategyIV) OperationB() {
	fmt.Println("策略4 实现的 OperationB")
}

func (this ConcreteStrategyIV) OperationC() {
	fmt.Println("策略4 实现的 OperationC")
}

实体类:

type Model struct {
	strategyI  Strategy1
	strategyII Strategy2
	otherAttr  string
}

func (this Model) DoSomething() {
	fmt.Print("执行策略1时:")
	this.strategyI.OperationA()
	fmt.Print("执行策略2时:")
	this.strategyII.OperationC()
	this.strategyII.OperationB()
	fmt.Printf("其他操作:%v", this.otherAttr)
}

func NewModel(strategy1 Strategy1, strategy2 Strategy2, attr string) Model {
	return Model{
		strategyI:  strategy1,
		strategyII: strategy2,
		otherAttr:  attr,
	}
}

测试:

package main

import (
	"DemoProject/design/base23/strategy" // 根据自己的项目路径定制
	"fmt"
)

func main() {
	// strategy
	model1 := strategy.NewModel(strategy.ConcreteStrategyI{}, strategy.ConcreteStrategyIII{}, "收尾工作1")
	model1.DoSomething()

	fmt.Println("=========================================")

	model2 := strategy.NewModel(strategy.ConcreteStrategyII{}, strategy.ConcreteStrategyIV{}, "收尾工作2")
	model2.DoSomething()
}

注意事项:

关键:分析项目中 变化部分不变部分

核心思想

  • 多用 组合/聚合,少用 继承
  • 行为类组合,而不是 行为的继承

体现了 “对修改关闭,对扩展开放” 原则,
Client 增加行为 不用 修改原有代码,只要 添加一种策略(或者行为) 即可,避免了使用 多重转移语句(if..else if..else)

提供了 可以替换继承关系 的办法:
策略模式 将 算法 封装在 独立的 Strategy 类 中,使得用户可以 独立于其 Context 改变它,使它 易于切换易于理解易于扩展

需要注意的是:每添加一个策略 就要 增加一个类,当 策略过多 是会导致 类数目庞大

本例中的示例可能看起来很像其实此处非常像 模板方法模式组合模式,如果区分不清的同学,可以参考这篇博文:
《Go 策略模式讲解和代码示例》
其中运用到的 缓存过期算法 就采用了 策略模式 进行的实现
例子相对更加清晰直观

posted @ 2021-12-17 10:47  在下右转,有何贵干  阅读(241)  评论(0)    收藏  举报