实践GoF的设计模式:代理模式

实践GoF的设计模式:代理模式

摘要: 代理模式为一个对象提供一种代理以控制对该对象的访问。

本文分享自华为云社区《【Go实现】实践GoF的23种设计模式:代理模式》,作者:元闰子 。

简介

GoF 对代理模式(Proxy Pattern)的定义如下:

Provide a surrogate or placeholder for another object to control access to it.

也即,代理模式为一个对象提供一种代理以控制对该对象的访问。

它是一个使用率非常高的设计模式,在现实生活中,也是很常见。比如,演唱会门票黄牛。假设你需要看一场演唱会,但官网上门票已经售罄,于是就当天到现场通过黄牛高价买了一张。在这个例子中,黄牛就相当于演唱会门票的代理,在正式渠道无法购买门票的情况下,你通过代理完成了该目标。

从演唱会门票的例子我们也能看出,使用代理模式的关键在于,当 Client 不方便直接访问一个对象时,提供一个代理对象控制该对象的访问。Client 实际上访问的是代理对象,代理对象会将 Client 的请求转给本体对象去处理。

UML 结构

场景上下文

在简单的分布式应用系统(示例代码工程)中,db 模块用来存储服务注册和监控信息,它是一个 key-value 数据库。为了提升访问数据库的性能,我们决定为它新增一层缓存:

另外,我们希望客户端在使用数据库时,并不感知缓存的存在,这些,代理模式可以做到。

代码实现

// demo/db/cache.go
package db
// 关键点1: 定义代理对象,实现被代理对象的接口
type CacheProxy struct {
 // 关键点2: 组合被代理对象,这里应该是抽象接口,提升可扩展性
 db    Db
    cache sync.Map // key为tableName,value为sync.Map[key: primaryId, value: interface{}]
    hit   int
 miss  int
}
// 关键点3: 在具体接口实现上,嵌入代理本身的逻辑
func (c *CacheProxy) Query(tableName string, primaryKey interface{}, result interface{}) error {
    cache, ok := c.cache.Load(tableName)
 if ok {
 if record, ok := cache.(*sync.Map).Load(primaryKey); ok {
 c.hit++
            result = record
 return nil
 }
 }
 c.miss++
 if err := c.db.Query(tableName, primaryKey, result); err != nil {
 return err
 }
 cache.(*sync.Map).Store(primaryKey, result)
 return nil
}
func (c *CacheProxy) Insert(tableName string, primaryKey interface{}, record interface{}) error {
 if err := c.db.Insert(tableName, primaryKey, record); err != nil {
 return err
 }
    cache, ok := c.cache.Load(tableName)
 if !ok {
 return nil
 }
 cache.(*sync.Map).Store(primaryKey, record)
 return nil
}
...
// 关键点4: 代理也可以有自己特有方法,提供一些辅助的功能
func (c *CacheProxy) Hit() int {
 return c.hit
}
func (c *CacheProxy) Miss() int {
 return c.miss
}
...
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 实践GoF的设计模式:代理模式