go实现策略模式

本文介绍了Go语言中策略模式的定义、结构图和实际应用案例。通过对比不同版本的商场收银软件,展示了策略模式如何解决代码重复、单一职责原则等问题,提高代码的灵活性和可扩展性。同时,文章探讨了策略模式的使用场景、优点,如遵循开闭原则和里氏替换原则,以及可能的缺点,如客户端需了解所有策略。最后,对策略模式进行了总结,强调其在选择和切换算法策略时的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

定义

定义了算法(一些列实现不同功能的方法)家族,分别封装起来,让它们之间相互可以替换,此模式让算法的变化,不会影响到使用算法的客户。

策略模式结构图

解释

Strategy:策略类,定义所有的算法子类支持的算法的公共接口。

Context:上下文类,维护一个策略Strategy对象的引用,在上下文类中,用一个方法来调用不同的算法类的方法。

ConcreteStrategy:封装了具体的算法或行为的类,都继承了Strategy类。

案例

做一个商场收银软件,根据客户购买的商品以及商场不同的营销模式,比如说满500减20,商品打八折等,向客户收费。

版本1.0

type Product struct {
	Num      int64
	Price    float64
	Discount float64
}

func Pay(product *Product, str string) (res float64) {
	switch str {
	case "原价":
		return float64(product.Num) * product.Price * product.Discount
	case "打八折":
		return float64(product.Num) * product.Price * product.Discount
	case "打七折":
		return float64(product.Num) * product.Price * product.Discount
	case "满200减10块":
		total := float64(product.Num) * product.Price * product.Discount
		if total >= 200 {
			return total - 20
		}
		return total
	default:
		return float64(product.Num) * product.Price * product.Discount
	}
}

func main() {
	product := &Product{
		Num:      20,
		Price:    3,
		Discount: 0.8,
	}
	fmt.Println(Pay(product, "打八折"))
}

缺点:

1.代码重复比价多

2.不符合单一职责原则,所有的计算商品的总价都放在一个函数内实现

3.违反了开闭原则 :对扩展是开放的,对修改是封闭的,即增加新的功能是不要修改原来的模块和源代码。

版本2.0

1、定义策略类

// Strategy 1.定义策略类,并且定义公共算法接口
type Strategy interface {
	AlgorithmInterface()
}

2、定义封装了具体的算法或方法的类,实现Strategy接口

func (concreteStrategyA *ConcreteStrategyA) AlgorithmInterface() {
	fmt.Println("实现算法a")
}

type ConcreteStrategyB struct {
}

func (concreteStrategyB *ConcreteStrategyB) AlgorithmInterface() {
	fmt.Println("实现算法b")
}

type ConcreteStrategyC struct {
}

func (concreteStrategyC *ConcreteStrategyC) AlgorithmInterface() {
	fmt.Println("实现算法c")
}

 3、定义context类,用一个concreteStrategy来配置,维护strategy对象的引用

func main() {
	ctx := new(Contexts)
    // 由于实例化的是不同的策略对象,所以最终调用公共方法是获得结果是不同的
	ctx = ctx.NewContexts(new(ConcreteStrategyA))
	ctx.ContextInterface()

	ctx = ctx.NewContexts(new(ConcreteStrategyB))
	ctx.ContextInterface()

	ctx = ctx.NewContexts(new(ConcreteStrategyC))
	ctx.ContextInterface()

}

4、测试

func main() {
	ctx := new(Contexts)

	ctx.strategy = new(ConcreteStrategyA)
	ctx.ContextInterface()

	ctx.strategy = new(ConcreteStrategyB)
	ctx.ContextInterface()

	ctx.strategy = new(ConcreteStrategyC)
	ctx.ContextInterface()

}

版本3.0 :使用简单工厂+策略模式解决策略对象有客户端创建的弊端

import "fmt"

func main() {
	ctx := new(Contexts)

	ct := ctx.NewContexts("a")
	ct.ContextInterface()

}

// Strategy 1.定义策略类,并且定义公共算法接口
type Strategy interface {
	AlgorithmInterface()
}

type ConcreteStrategyA struct {
}

func (concreteStrategyA *ConcreteStrategyA) AlgorithmInterface() {
	fmt.Println("实现算法a")
}

type ConcreteStrategyB struct {
}

func (concreteStrategyB *ConcreteStrategyB) AlgorithmInterface() {
	fmt.Println("实现算法b")
}

type ConcreteStrategyC struct {
}

func (concreteStrategyC *ConcreteStrategyC) AlgorithmInterface() {
	fmt.Println("实现算法c")
}

type Contexts struct {
	strategy Strategy // 类的嵌入
}

// NewContexts 类似于Java中的构造函数
func (ctx *Contexts) NewContexts(typ string) *Contexts {
	contexts := new(Contexts)
	switch typ {
	case "a":
		concreteStrategyA := new(ConcreteStrategyA)
		contexts.strategy = concreteStrategyA
		return contexts
	case "b":
		concreteStrategyB := new(ConcreteStrategyB)
		contexts.strategy = concreteStrategyB
		return contexts
	case "c":
		concreteStrategyC := new(ConcreteStrategyC)
		contexts.strategy = concreteStrategyC
		return contexts
	default:
		return nil
	}
}

func (ctx *Contexts) ContextInterface() {
	ctx.strategy.AlgorithmInterface()
}

 优点:如果仅仅使用工厂模式,客户端需要理解Contexts类和各个策略类,但是如果使用简单工厂+策略模式,客户端仅仅只需理解Contexts类即可,类的创建也封装到了Contexts的构造方法中了。

使用场景

1.策略模式体现了开闭原则:策略模式把一系列的可变算法进行封装,从而定义了良好的程序结构,在出现新的算法的时候,可以很容易的将新的算法实现加入到已有的系统中,而已有的实现不需要修改

2.策略模式体现了里氏替换原则:策略模式是一个扁平的结构,各个策略实现都是兄弟关系,实现了同一个接口或者继承了同一个抽象类。这样只要使用策略的客户端保持面向抽象编程,就可以动态的切换不同的策略实现以进行替换。

优缺点

优点

1.就是把具体的算法实现从业务逻辑中剥离出来,成为一系列独立算法类,使得它们可以相互替换。

2.不是如何来实现算法,而是如何组织和调用这些算法,从而让我们的程序结构更加的灵活、可扩展

3.策略模式就是把各个平等的具体实现进行抽象、封装成为独立的算法类,然后通过上下文和具体的算法类来进行交互。各个策略算法都是平等的,地位是一样的,正是由于各个算法的平等性,所以它们才是可以相互替换的。虽然我们可以动态的切换各个策略,但是同一时刻只能使用一个策略。

缺点

1..客户端必须了解所有的策略,清楚它们的不同,然后使用不同的策略,即把策略对象的创建又交给了客户端

2、增加了对象的数量,由于每一个策略都是一个策略类。

3、只适合同一个客户端同一时刻只使用一个策略。这些策略是平等的。

总结

1.策略和上下文的关系:在策略模式中,一般情况下都是上下文持有策略的引用,以进行对具体策略的调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值