装饰器模式

Go设计模式总结

基本原则

  • 单一原则

每个模块实现的功能要尽可能简单

  • 开闭原则

尽量不要改动上版本的代码

  • 面向接口开发

面向接口来实现多态开发,而不是面向类来开发

基本汇总

大部分的设计模式在Go中共有下面几种方式实现

  • 使用 interface

Go中 interface 还是个万能的数据类型,类似 c 语言的 void 指针

  • 用 interface 实现 多态

这个是最基本的也是经常用到的功能,结合 struct 实现

  • 多个 interface 和 多个多态结合

大部分设计模式就是通过这个实现的

装饰器模式

装饰器模式,一种不改变原有代码,却能增加功能的设计模式。

闭包简单实现

首先实现一个简单的逻辑

用闭包来实现装饰器

像下面实现了 work01 的业务处理

type Work func()

func work01() Work{
	return func() {
		fmt.Println("处理 work01 业务逻辑")
	}
}

func main() {
	work := work01()
	work()
}

接着需要添加 work02 的业务逻辑

要在 work01 处理之前处理 work02

这时可以这么处理

func work02(fn Work) Work {
	return func(){
		fmt.Println("处理 work02 业务逻辑")
		// 实现原始功能
		fn()
	}
}

main 函数变成这样子

这个时候我们就不修改原代码的情况下添加了 work02 业务逻辑,并且是在执行了work02 后才执行 work01

func main() {
	work := work01()
	work = work02(work)
	work()
}

接着需求又要增加 work03 的功能

需要在 work01 之后执行 work03 功能

这时候实现和上面类似

func work03(fn Work) Work {
	return func(){
		// 实现原始功能
		fn()
		fmt.Println("处理 work03 业务逻辑")
	}
}

main函数现在变成了这个样子

func main() {
	work := work01()
	work = work02(work)
	work = work03(work)
	work()
}

这时候就完成了简单的装饰器模式,不改变原代码的情况下增加功能,更多情况以此类推

像上面的例子经常可以用在web开发中,在处理业务之前开启事物,业务处理完毕后提交事物或者回滚事物

接口简单实现

和上面的逻辑类似,不过这里用接口来处理,因为开发中经常用类和接口

同样在第一版本中实现个简单的功能,这里用接口和多态来实现,这个是最基本和最常用的

type Work interface {
	Do()
}

type Work01 struct {}

func (w *Work01)Do() {
	fmt.Println("处理 work01 业务逻辑")
}

func main() {
	var work Work = &Work01{}
	work.Do()
}

接着在第二版本中需要增加 work02 功能,在 work01 执行完之后执行 work02

type Work02 struct {
	Work
	// 定义其他数据
}

func (w *Work02)Do()  {
	// 实现原始功能
	w.Work.Do()
	fmt.Println("处理 work02 业务逻辑")
}

// 装饰work02
func Work02Decorator(w Work) Work {
	return &Work02{w}
}

main 函数变成这样子

func main() {
	var work Work = &Work01{}
	work = Work02Decorator(work)
	work.Do()
}

接着在第三个版本中增加 work03 功能,执行完 work02 后执行 work03

type Work03 struct {
	Work
	// 定义其他数据
}

func (w *Work03)Do()  {
	// 实现原始功能
	w.Work.Do()
	fmt.Println("处理 work03 业务逻辑")
}

// 装饰work03
func Work03Decorator(w Work) Work {
	return &Work03{w}
}

main 函数变成如下这样子

func main() {
	var work Work = &Work01{}
	work = Work02Decorator(work)
	work = Work03Decorator(work)
	work.Do()
}

这样就用接口来实现了装饰器模式

电商项目中订单的金额结算案例

一般刚开始开发项目时,比如在第一个版本中,为了快速出成果,一般是比较简单的功能,比如订单金额结算其实就直接是商品价格*数量

但在后面版本迭代中,可能就会出现其他功能,比如运费、优惠券、满减等,而且这些功能可能还比较复杂

一般情况下是尽可能不动上一个版本的代码的,因为上一个版本经过测试上线等,说明是没什么问题的,而如果改动了上一个版本的代码,可能会出现技术上的bug或者业务逻辑上的错误

像这种情况就可以用装饰器模式来实现

首先我们来实现第一版本的简单逻辑,先定义订单数据和支付金额的接口

type Order struct {
	// 支付总金额
	PayMoney float32
	// 商品总金额
	Money float32
}

type MoneySum interface {
	// 支付金额
	Sum(order *Order)
}

接着实现支付功能,逻辑就直接是商品金额*数量了

type OrderPay struct {
	// 定义其他数据
}

func (o *OrderPay)Sum(order *Order)  {
	// 假设 商品价格为100,数量为5
	order.PayMoney = 100 * 5
	order.Money = 100 * 5
}

mian 函数如下,这就完成了第一版本的金额结算

func main() {
	order := Order{}
	var moneySum MoneySum = &OrderPay{}
	moneySum.Sum(&order)
	fmt.Printf("支付总金额为:%v,商品总金额为:%v",order.PayMoney,order.Money)
}

接着在第二版本中增加满减优惠,增加功能如下

type FullMoney struct {
	MoneySum
	// 定义其他数据
}

func (f *FullMoney)Sum(order *Order) {
	// 实现原始功能
	f.MoneySum.Sum(order)
	// 满减优惠
	if order.PayMoney > 200 {
		order.PayMoney -= 50
	}
}

// 满减装饰
func FullMoneyDecorator(m MoneySum) MoneySum {
	return &FullMoney{m}
}

此时 main 如下

func main() {
	order := Order{}
	var moneySum MoneySum = &OrderPay{}
	moneySum = FullMoneyDecorator(moneySum)
	moneySum.Sum(&order)
	fmt.Printf("支付总金额为:%v,商品总金额为:%v",order.PayMoney,order.Money)
}

这样子就很完美的增加了第二版本的内容

上面的实现是尽可能简单化,实际开发中每个类在各自的包中,实现自个的方法和定义自个的数据

其他的运费、优惠券等以此类推

redis 缓存封装案例

待更

参考

git项目地址

posted @ 2020-09-02 00:36  Python++  阅读(147)  评论(0编辑  收藏  举报