问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Go语言代理模式详解:概念、特点与实战示例

创作时间:
作者:
@小白创作中心

Go语言代理模式详解:概念、特点与实战示例

引用
CSDN
1.
https://blog.csdn.net/LuckyLay/article/details/145745256

代理模式是一种常用的设计模式,通过引入代理对象间接访问真实对象,从而在不修改原对象代码的前提下,控制访问或增强功能。本文将详细介绍代理模式的核心概念、特点分析、适用场景,并通过Go语言代码示例帮助读者深入理解这一模式。

一、核心概念

1. 定义

代理模式(Proxy Pattern)是一种结构型设计模式,通过引入代理对象间接访问真实对象,从而在不修改原对象代码的前提下,控制访问增强功能(如日志、缓存、权限校验)。

2. 解决的问题

  • 访问控制:限制对真实对象的直接访问(如权限校验)
  • 功能扩展:在调用真实对象前后添加额外逻辑(如日志、缓存)
  • 资源优化:延迟加载高开销对象(如大文件、远程服务)

3. 核心角色

  1. Subject(抽象主题)
    定义真实对象和代理的公共接口(如
    UserService
    接口)
  2. RealSubject(真实主题)
    实现具体业务逻辑(如
    RealUserService
    处理数据库查询)
  3. Proxy(代理)
    持有真实对象的引用,并添加增强逻辑(如缓存代理
    UserServiceProxy

4. 类图

二、特点分析

优点

  1. 职责分离:代理处理非核心逻辑(如日志),真实对象专注业务
  2. 扩展性强:新增代理不影响原有代码,符合开闭原则
  3. 资源保护:通过代理控制敏感操作(如权限校验)

缺点

  1. 性能损耗:动态代理(如反射)可能降低执行效率
  2. 复杂度增加:需维护代理与真实对象的关系

三、适用场景

  1. 权限控制:接口调用前的身份验证
  2. 延迟加载:按需加载大资源(如图片、文件)
  3. 日志监控:记录方法调用参数和结果
  4. 远程调用:RPC框架通过代理隐藏网络细节

四、代码示例(Go语言)

1. 文件下载代理(含权限校验)

package proxydemo
import "fmt"
// 抽象主题 文件接口
type File interface {
   Download()
}
// 真实主题 真实文件
type RealFile struct {
   Name string
}
func (r *RealFile) Download() {
   fmt.Println("Downloading " + r.Name)
}
// 代理:文件代理
type FileProxy struct {
   realFile *RealFile
   userRole string
}
func NewFileProxy(filename, role string) *FileProxy {
   return &FileProxy{
      realFile: &RealFile{Name: filename},
      userRole: role,
   }
}
func (f *FileProxy) Download() {
   if f.userRole == "admin" {
      f.realFile.Download()
   } else {
      fmt.Println("You don't have permission to download " + f.realFile.Name)
   }
}
func test_downloadFile(role string) {
   adminFile := NewFileProxy("adminFile.txt", role)
   adminFile.Download()
}

测试方法

package proxydemo
import "testing"
func Test_test_downloadFile(t *testing.T) {
    type args struct {
        role string
    }
    tests := []struct {
        name string
        args args
    }{
        {
            name: "admin",
            args: args{
                role: "admin",
            },
        },
        {
            name: "user",
            args: args{
                role: "user",
            },
        },
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            test_downloadFile(tt.args.role)
        })
    }
}

输出结果:

=== RUN   Test_test_downloadFile
=== RUN   Test_test_downloadFile/admin
Downloading adminFile.txt
=== RUN   Test_test_downloadFile/user
You don't have permission to download adminFile.txt
--- PASS: Test_test_downloadFile (0.00s)
    --- PASS: Test_test_downloadFile/admin (0.00s)
    --- PASS: Test_test_downloadFile/user (0.00s)
PASS

2. 缓存代理(用户信息查询)

package proxydemo
import "fmt"
type UserService interface {
   GetUser(id int) (string, error)
}
type RealUserService struct{}
func (r *RealUserService) GetUser(id int) (string, error) {
   // 模拟从数据库中获取用户信息
   return fmt.Sprintf("User%d", id), nil
}
type CachedUserService struct {
   realService UserService
   cache       map[int]string
}
func NewCachedUserService() *CachedUserService {
   return &CachedUserService{
      realService: &RealUserService{},
      cache:       make(map[int]string),
   }
}
func (c *CachedUserService) GetUser(id int) (string, error) {
   if user, ok := c.cache[id]; ok {
      fmt.Println("Returning user from cache")
      return user, nil
   }
   fmt.Println("Fetching user from real service")
   user, err := c.realService.GetUser(id)
   if err != nil {
      return "", err
   }
   c.cache[id] = user
   return user, nil
}
func test_cache() {
   cachedService := NewCachedUserService()
   user, _ := cachedService.GetUser(1)
   fmt.Println("User:", user)
   fmt.Println("-----------------")
   user, _ = cachedService.GetUser(1)
   fmt.Println("User:", user)
}

输出结果

=== RUN   Test_test_cache
Fetching user from real service
User: User1
-----------------
Returning user from cache
User: User1
--- PASS: Test_test_cache (0.00s)
PASS

五、高级应用

  1. 动态代理
    Go可通过反射实现动态代理(需处理性能损耗):
func DynamicProxy(target interface{}, preHandler func()) interface{} {
    val := reflect.ValueOf(target)
    return reflect.New(val.Type()).Interface()
}
  1. 组合代理链
    多个代理嵌套使用(如先鉴权再缓存):
authProxy := NewAuthProxy(userRole)
cachedProxy := NewCachedProxy(authProxy)
cachedProxy.Download()

六、与其他模式对比

模式
核心目标
关键区别
装饰器
动态添加功能
关注功能叠加
适配器
接口转换
解决兼容性问题
代理
控制访问/增强前置后置逻辑
侧重访问限制和流程控制

七、总结

代理模式通过间接访问逻辑增强,解决了以下问题:

  1. 安全控制:通过代理拦截非法请求
  2. 功能扩展:无侵入式添加日志、缓存等逻辑
  3. 资源优化:延迟加载降低系统开销

在Go中实现时需注意:

  • 优先使用接口定义抽象主题
  • 代理与真实对象需实现相同接口
  • 避免过度使用动态代理(反射有性能损耗)
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号