Go设计模式(11)-代理模式

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 从本篇文章开始讲解结构型模式,结构型模式主要总结了一些类或对象组合在一起的经典结构,这些经典的结构可以解决特定应用场景的问题。

前面通过5篇文章讲解了创建型模式,创建型模式主要解决对象的创建问题,封装复杂的创建过程,解耦对象的创建代码和使用代码。

  1. Go设计模式(6)-单例模式:用于创建全局唯一对象
  2. Go设计模式(7)-工厂模式:用于根据参数,创建不同但是相关类型的对象
  3. Go设计模式(8)-抽象工厂:用于创建对象时,减少工厂类个数,增加可维护性
  4. Go设计模式(9)-建造者模式:用于创建复杂对象
  5. 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. 使用场景

使用代理模式的场景有以下这些:

  1. 业务系统的非功能性需求开发:如监控、统计、鉴权、限流、事务、幂等、日志等,这些和业务没有关系,所以可以放到Proxy中,RealSubject只关注功能性需求。

    以前写过一篇文章如何高效对接第三方支付,公司对接了大量的第三方支付公司(PayU、PayTM、WX),这些公司发起支付的流程是一样的,核心是获取token,但是还要做很多琐碎、通用的工作,如校验签名、初始化订单数据、参数检查、记录日志等。这些琐碎功能如果让每一个支付类自己处理,不但是重复开发,而且后期修改时不易维护,这时候就很适合用代理模式。

图片

  1. 框架设计,如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/

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2月前
|
设计模式 缓存 安全
设计模式——代理模式
静态代理、JDK动态代理、Cglib 代理
设计模式——代理模式
|
2月前
|
设计模式 Java 数据安全/隐私保护
Java设计模式-代理模式(7)
Java设计模式-代理模式(7)
|
3月前
|
设计模式 缓存 Java
【十一】设计模式~~~结构型模式~~~代理模式(Java)
文章详细介绍了代理模式(Proxy Pattern),这是一种对象结构型模式,用于给对象提供一个代理以控制对它的访问。文中阐述了代理模式的动机、定义、结构、优点、缺点和适用环境,并探讨了远程代理、虚拟代理、保护代理等不同代理形式。通过一个商务信息查询系统的实例,展示了如何使用代理模式来增加身份验证和日志记录功能,同时保持客户端代码的无差别对待。此外,还讨论了代理模式在分布式技术和Spring AOP中的应用,以及动态代理的概念。
【十一】设计模式~~~结构型模式~~~代理模式(Java)
|
3月前
|
设计模式 Go
go 设计模式之观察者模式
go 设计模式之观察者模式
|
3月前
|
设计模式
设计模式的基础问题之代理模式在工作中的问题如何解决
设计模式的基础问题之代理模式在工作中的问题如何解决
|
4月前
|
设计模式 Go
Go语言设计模式:使用Option模式简化类的初始化
在Go语言中,面对构造函数参数过多导致的复杂性问题,可以采用Option模式。Option模式通过函数选项提供灵活的配置,增强了构造函数的可读性和可扩展性。以`Foo`为例,通过定义如`WithName`、`WithAge`、`WithDB`等设置器函数,调用者可以选择性地传递所需参数,避免了记忆参数顺序和类型。这种模式提升了代码的维护性和灵活性,特别是在处理多配置场景时。
69 8
|
3月前
|
缓存 中间件 应用服务中间件
|
4月前
|
设计模式 算法 Go
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
|
4月前
|
设计模式 缓存 JavaScript
js设计模式【详解】—— 代理模式
js设计模式【详解】—— 代理模式
30 0
|
5月前
|
设计模式 监控 安全
设计模式之代理模式(Java)
设计模式之代理模式(Java)