Golang学习笔记_32——适配器模式
Golang学习笔记_33——桥接模式
Golang学习笔记_34——组合模式
文章目录
一、核心概念
1. 定义
代理模式(Proxy Pattern)是一种结构型设计模式,通过引入代理对象间接访问真实对象,从而在不修改原对象代码的前提下,控制访问或增强功能(如日志、缓存、权限校验)。
2. 解决的问题
- 访问控制:限制对真实对象的直接访问(如权限校验)
- 功能扩展:在调用真实对象前后添加额外逻辑(如日志、缓存)
- 资源优化:延迟加载高开销对象(如大文件、远程服务)
3. 核心角色
- Subject(抽象主题)
定义真实对象和代理的公共接口(如UserService
接口) - RealSubject(真实主题)
实现具体业务逻辑(如RealUserService
处理数据库查询) - Proxy(代理)
持有真实对象的引用,并添加增强逻辑(如缓存代理UserServiceProxy
)
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
五、高级应用
动态代理
Go可通过反射实现动态代理(需处理性能损耗):func DynamicProxy(target interface{}, preHandler func()) interface{} { val := reflect.ValueOf(target) return reflect.New(val.Type()).Interface() }
组合代理链
多个代理嵌套使用(如先鉴权再缓存):authProxy := NewAuthProxy(userRole) cachedProxy := NewCachedProxy(authProxy) cachedProxy.Download()
六、与其他模式对比
模式 | 核心目标 | 关键区别 |
---|---|---|
装饰器 | 动态添加功能 | 关注功能叠加 |
适配器 | 接口转换 | 解决兼容性问题 |
代理 | 控制访问/增强前置后置逻辑 | 侧重访问限制和流程控制 |
七、总结
代理模式通过间接访问和逻辑增强,解决了以下问题:
- 安全控制:通过代理拦截非法请求
- 功能扩展:无侵入式添加日志、缓存等逻辑
- 资源优化:延迟加载降低系统开销
在Go中实现时需注意:
- 优先使用接口定义抽象主题
- 代理与真实对象需实现相同接口
- 避免过度使用动态代理(反射有性能损耗)