深入理解Go设计模式之代理模式

 更新时间:2023年05月30日 08:59:54   作者:kevinyan  
代理模式是一种结构型设计模式, 其中代理控制着对于原对象的访问, 并允许在将请求提交给原对象的前后进行一些处理,从而增强原对象的逻辑处理,这篇文章主要来学习一下代理模式的构成和用法,需要的朋友可以参考下

什么是代理模式

代理模式是一种结构型设计模式。 其中代理控制着对于原对象的访问, 并允许在将请求提交给原对象的前后进行一些处理,从而增强原对象的逻辑处理。

上面的代理者我们一般叫做代理对象或者直接叫做代理-- Proxy,进行逻辑处理的原对象通常被称作服务对象,代理要跟服务对象实现相同的接口,才能让客户端傻傻分不清自己使用的到底是代理还是真正的服务对象,这样一来代理就能在客户端察觉不到的情况下对服务对象的处理逻辑进行增强。

什么叫对处理逻辑进行增强?或者换一种说法,叫对核心功能添加增强功能?举个例子来说,处理客户端查询用户订单信息的 API Handler 就是核心处理逻辑,增强逻辑就是我们需要在查询订单信息之前,验证请求是否是有效用户、记录请求的参数和返回的响应数据等等。

看了上面代理模式的解释,你可能还是觉得有点宽泛,下面咱们写一个简单的代码示例,这个过程中你差不多就会发现:“诶,原来这就是代理模式啊,我之前写代码的时候早就用过了~!” 下面我们一起开下这个例子吧。

代理模式使用演示

假设有一个代表小汽车的 Car 类型

type Car struct{}

小汽车要的主要行为就是可以让人驾驶,所以 Car 需要实现一个代表驾驶行为的接口(interface)Vehicle,该接口只有一个方法Drive()

type Vehicle interface {
    Drive()
}
type Car struct{}
func (c *Car) Drive() {
    fmt.Println("Car is being driven")
}

Car 的结构体指针通过实现Drive()方法实现了Vehicle接口。

现在我们只要实例化一个Car的实例,在实例上面调用Drive()方法就能让车开起来,不过如果我们的驾驶员现在还是个未成年,那么在地球的大部分国家都是不允许开车的,如果在开车时要加一个驾驶员的年龄限制,我们该怎么办呢? 给Car结构体加一个Age字段显然是不合理的,因为我们要表示的驾驶员的年龄而不是车的车龄。同理驾驶员年龄的判断我们也不应该加在 Car 实现的 Drive() 方法里, 这样会导致每个实现 Vehicle 接口的类型都要在自己的 Drive() 方法里加上类似的判断。

这个时候通常的做法是,加一个表示驾驶员的类型 Driver

type Driver struct {
    Age int
}

然后再来一个包装 Driver 和 Vehicle 类型的包装类型。

type CarProxy struct {
    vehicle    Vehicle
    driver *Driver
}
func NewCarProxy(driver *Driver) *CarProxy {
    return &CarProxy{&Car{}, driver}
}

这样的话我们接可以通过,用包装类型代理vehicle属性的 Drive() 行为时,给它加上驾驶员的年龄限制。

func (c *CarProxy) Drive() {
    if c.driver.Age >= 16 {
        c.vehicle.Drive()
    } else {
        fmt.Println("Driver too young!")
    }
}

我相信这个编程技巧大家在平时开发中都用过,这个其实就是代理模式。

现在我们通过代理模式给 Car 类型的 Drive() 行为扩充了检查驾驶员的行为,下面我们执行一下程序试试效果。

func main() {
	car := NewCarProxy(&Driver{12})
	car.Drive() // 输出 Driver too young!
	car2 := NewCarProxy(&Driver{22})
	car2.Drive() // 输出 Car is being driven
}

正如执行后的结果所示,我们不必为服务对象 -- Car 类型添加任何属性和方法。相反,我们只是在其上面的代理层把客户端 Drive() 方法的调用委托(英文术语叫delegate)给了其 vehicle 属性的 Drive 方法,并在之前添加了年龄检查行为,从而达到我们想要的效果。

看完例子后,相信大家都理解了写代码时怎么使用代理模式,下面我们从代码走出来,再更清晰的描述下代理模式它的整体结构。

看清代理模式

根据上面一开始的描述和后面的代码例子,我们总结出来,参与代理模式的一共有四种角色:客户端、服务接口、服务类和代理类,他们之间的关系用 UML 类图表示如下:

上面 UML 类图一共有四个角色,这四个角色在代理模式中的职责分别是。

  • 服务接口 (Ser­vice Inter­face) 声明了服务类要实现的接口。 服务类的业务处理逻辑就是实现在这里定义的接口方法中,代理类也必须遵循该接口才能伪装成服务对象。
  • 服务 (Ser­vice) 类,就是上面说的,提供实际业务逻辑的原对象。
  • 代理 (Proxy) 类包含一个服务对象作为成员变量。 代理完成其任务 (例如延迟初始化、记录日志、 访问控制和缓存等)后面会将请求传递给服务对象。通常情况下, 代理会对其服务对象的整个生命周期进行管理,来增强服务对象,这样与核心业务逻辑不相关的增强逻辑就可以由代理来实现
  • 客户端 (Client) 通过统一接口与服务或代理进行交互, 所以可在一切需要服务对象的代码中使用服务对象的代理,客户端完全不会感知到。

代理模式延伸

在代理模式中,通过让代理类实现跟服务类相同的接口,从而把代理类伪装成了服务类,客户端请求代理时,代理再把请求委派给其持有的真实服务类,在委派的过程中我们就可以添加增强逻辑。 那么如果我们再给代理类加个代理,代理的代理再加代理,那么其实就变成了另外一种设计模式--装饰器模式啦,其实装饰器模式本身就是代理模式的一个特殊应用,关于装饰器的内容,我们放到后面进行学习。

以上就是深入理解Go设计模式之代理模式的详细内容,更多关于Go 代理模式的资料请关注脚本之家其它相关文章!

相关文章

  • Go语言实现字符串搜索算法Boyer-Moore

    Go语言实现字符串搜索算法Boyer-Moore

    Boyer-Moore 算法是一种非常高效的字符串搜索算法,被广泛的应用于多种字符串搜索场景,下面我们就来学习一下如何利用Go语言实现这一字符串搜索算法吧
    2023-11-11
  • 浅析Go语言中数组的这些细节

    浅析Go语言中数组的这些细节

    这篇文章主要为大家详细介绍了Go语言中数组一些细节的相关资料,文中的示例代码讲解详细,对我们学习Go语言有一定的帮助,需要的可以了解一下
    2022-11-11
  • Golang配置解析神器go viper使用详解

    Golang配置解析神器go viper使用详解

    viper是一个很完善的Go项目配置解决方案,很多著名的开源项目都在使用,比如Hugo,Docker都使用了该库,使用viper可以让我们专注于自己的项目代码,而不用自己写那些配置解析代码,本文给大家介绍Golang配置解析神器go viper使用,感兴趣的朋友一起看看吧
    2022-05-05
  • Golang创建第一个web项目(Gin+Gorm)

    Golang创建第一个web项目(Gin+Gorm)

    本文主要介绍了Golang创建第一个web项目(Gin+Gorm),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-06-06
  • 十个Golang开发中应该避免的错误总结

    十个Golang开发中应该避免的错误总结

    Go是一种静态类型的、并发的、垃圾收集的编程语言,由谷歌开发。开发人员在编写Go代码时总会有一些常见的错误,下面是Go语言中需要避免的十大坏错误,希望对大家有所帮助
    2023-03-03
  • golang如何通过viper读取config.yaml文件

    golang如何通过viper读取config.yaml文件

    这篇文章主要介绍了golang通过viper读取config.yaml文件,围绕golang读取config.yaml文件的相关资料展开详细内容,需要的小伙伴可以参考一下
    2022-03-03
  • Go语言JSON解析器gjson使用方法详解

    Go语言JSON解析器gjson使用方法详解

    这篇文章主要介绍了Go语言json解析框架与gjson,JSON 解析是我们不可避免的常见问题,在Go语言中,我们可以借助gjson库来方便的进行json属性的提取与解析,需要的朋友可以参考一下
    2022-12-12
  • Go java 算法之括号生成示例详解

    Go java 算法之括号生成示例详解

    这篇文章主要为大家介绍了Go java 算法之括号生成示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • 超全讲解Golang中defer关键字的用法

    超全讲解Golang中defer关键字的用法

    本文将从一个资源回收问题引入,引出defer关键字,并对其进行基本介绍,从而让大家对Go语言中的defer有更深入的了解,需要的小伙伴可以学习一下
    2023-05-05
  • 从浅入深带你掌握Golang数据结构map

    从浅入深带你掌握Golang数据结构map

    在 Go 语言中,map 是一种非常常见的数据类型,它可以用于快速地检索数据。本篇文章将介绍 Go 语言中的 map,包括 map 的定义、初始化、操作和优化,需要的可以参考一下
    2023-04-04

最新评论