前面通过5篇文章讲解了创建型模式,创建型模式主要解决对象的创建问题,封装复杂的创建过程,解耦对象的创建代码和使用代码。
- Go设计模式(6)-单例模式:用于创建全局唯一对象
- Go设计模式(7)-工厂模式:用于根据参数,创建不同但是相关类型的对象
- Go设计模式(8)-抽象工厂:用于创建对象时,减少工厂类个数,增加可维护性
- Go设计模式(9)-建造者模式:用于创建复杂对象
- Go设计模式(10)-原型模式:用于创建成本较大的对象
从本篇文章开始讲解结构型模式,结构型模式主要总结了一些类或对象组合在一起的经典结构,这些经典的结构可以解决特定应用场景的问题。
代理模式能够在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。 一般代理类和被代理类有同一个父类。
本文UML类图链接为:https://www.processon.com/view/link/609b39d6f346fb5a37705da6
本文代码链接为:https://github.com/shidawuhen/asap/blob/master/controller/design/11proxy.go
1.定义
1.1代理模式
代理模式:为其他对象提供一种代理以控制对这个对象的访问。
UML类图:
1.2分析
看UML类图,可以看出代理类Proxy和被代理类RealSubject实现了相同接口Subject,代理类包含被代理类的引用。代理模式实现了在被代理类外面套了一层壳。虽然整体的设计和思想都很简单,但效果却很明显。首先在请求RealSubject的时候,必须经过Proxy,这样一些前置或者后置通用操作都可以放在Proxy中,扩展性和通用性都会加强。其次,因为Proxy和RealSubject各自实现了一部分功能,会使RealSubject更加关注自己的业务逻辑,起到很好的隔离效果。
2. 使用场景
使用代理模式的场景有以下这些:
- 业务系统的非功能性需求开发:如监控、统计、鉴权、限流、事务、幂等、日志等,这些和业务没有关系,所以可以放到Proxy中,RealSubject只关注功能性需求。
以前写过一篇文章如何高效对接第三方支付,公司对接了大量的第三方支付公司(PayU、PayTM、WX),这些公司发起支付的流程是一样的,核心是获取token,但是还要做很多琐碎、通用的工作,如校验签名、初始化订单数据、参数检查、记录日志等。这些琐碎功能如果让每一个支付类自己处理,不但是重复开发,而且后期修改时不易维护,这时候就很适合用代理模式。
- 框架设计,如RPC的实现。调用RPC客户端,客户端会自动调用RPC服务端,客户端也是一个代理,做了大量操作让开发者可以不关心是如何成功调用到服务端的,只需要关心逻辑实现即可。
3.代码实现
这里简单实现一下支付网关发起支付功能是如何使用代理模式的。
package main
import (
"fmt"
)
/**
* @Description: 支付接口,只包含发起支付功能
*/
type PaymentService interface {
pay(order string) string
}
/**
* @Description: 微信支付类
*/
type WXPay struct {
}
/**
* @Description: 微信支付类,从微信获取支付token
* @receiver w
* @param order
* @return string
*/
func (w *WXPay) pay(order string) string {
return "从微信获取支付token"
}
/**
* @Description: 阿里支付类
*/
type AliPay struct {
}
/**
* @Description: 阿里支付类,从阿里获取支付token
* @receiver a
* @param order
* @return string
*/
func (a *AliPay) pay(order string) string {
return "从阿里获取支付token"
}
/**
* @Description: 支付代理类
*/
type PaymentProxy struct {
realPay PaymentService
}
/**
* @Description: 做校验签名、初始化订单数据、参数检查、记录日志、组装这种通用性操作,调用真正支付类获取token
* @receiver p
* @param order
* @return string
*/
func (p *PaymentProxy) pay(order string) string {
fmt.Println("处理" + order)
fmt.Println("1校验签名")
fmt.Println("2格式化订单数据")
fmt.Println("3参数检查")
fmt.Println("4记录请求日志")
token := p.realPay.pay(order)
return "http://组装" + token + "然后跳转到第三方支付"
}
func main() {
proxy := &PaymentProxy{
realPay: &AliPay{},
}
url := proxy.pay("阿里订单")
fmt.Println(url)
}
输出为:
➜ myproject go run main.go
处理阿里订单
1校验签名
2格式化订单数据
3参数检查
4记录请求日志
http://组装从阿里获取支付token然后跳转到第三方支付
代码比较简单,但效果还是很好的,大家可以思考一下,如果再使用上Go设计模式(7)-工厂模式,是不是就全自动化了,今后接入新的第三方支付,只需要开发新的支付类,框架上几乎不需要修改,研发和测试的成本会降低很多。这也解释了设计模式的妙用。
总结
代理模式简单实用,使用得当能让系统可扩展性增强。它能帮助开发者实现具体业务和通用逻辑的分离,是开发者只需关注具体业务,满足开放-封闭、里氏替换、依赖倒转等原则。
最后
大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)
我的个人博客为:https://shidawuhen.github.io/