zoukankan      html  css  js  c++  java
  • 装饰器模式

    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项目地址

  • 相关阅读:
    目标检测之YOLOv3
    残差网络(ResNet)
    FPN详解
    YOLOv2/YOLO 9000深入理解
    批归一化(BN)
    全卷积网络FCN
    基于深度学习的目标检测算法综述
    目标检测两个基础部分——backbone and detection head
    YOLOv1 深入理解
    内置模块
  • 原文地址:https://www.cnblogs.com/GH-123/p/13599585.html
Copyright © 2011-2022 走看看