代理模式是结构型模式。结构型模式主要总结了一些类或对象组合在一起的经典结构,这些经典的结构可以解决特定应用场景的问题
原理和实现:
在不改变原始类(或叫被代理类)的情况下,通过引入代理类来给原始类附加功能。一般情况下,我们让代理类和原始类实现同样的接口。但是,如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的。在这种情况下,我们可以通过让代理类继承原始类的方法来实现代理模式
上面的这句话就说出来代理模式的两种应用,第一种是代理类和原始类都基于接口实现,这样实际应用的时候,只需要修改赋值给接口的类型由原始类改为代理类,代码改动比较小;还有一种是原始类是第三方,无法修改,无法基于接口实现,所以使用组合(或者说是继承)的方式让代理类继承原始类,但是这样代码改动比较大,所有用到原始类的地方都要替换成代理类
第一种基于接口实现如下
type IUser interface {
Login() string
Register() string
}
//原始类
type User struct {
}
//原始类业务方法,基于接口
func (u *User) Login() string {
//业务逻辑
return ""
}
func (u *User) Register() string {
//业务逻辑
return ""
}
//代理类
type UserProxy struct {
user *User
}
//代理类附加功能方法,基于接口
func (p *UserProxy) Login() string {
//附加功能
startTime := time.Now()
//原始类业务逻辑
res := p.user.Login()
//附加功能,记录请求时间上报
endTime := time.Now()
new(MetricCollector).record("login",endTime.Sub(startTime))
return res
}
func (p *UserProxy) Register() string{
//附加功能
startTime := time.Now()
//原始类业务逻辑
res := p.user.Register()
//附加功能,记录请求时间上报
endTime := time.Now()
new(MetricCollector).record("register",endTime.Sub(startTime))
return res
}
//信息上报类
type MetricCollector struct{
}
func (m *MetricCollector) record(info string,time time.Duration){
}
//依赖注入
func DoSomethingToUser(user IUser){
fmt.Println(user.Login())
fmt.Println(user.Register())
}
//实际应用
func testProxy(){
//u := &User{}
//原始类切换为代理类赋值给接口即可,代码改动小
u := &UserProxy{
user: &User{},
}
DoSomethingToUser(u)
}
第二种基于组合实现如下
// 原始类
type User struct {
}
// 原始类业务
func (u *User) Login() string {
//业务逻辑
return ""
}
func (u *User) Register() string {
//业务逻辑
return ""
}
//代理类
type UserProxy struct {
*User //组合,继承原始类的方法
}
func (p *UserProxy) Login() string {
//附加功能
startTime := time.Now()
//原始类业务逻辑
res := p.User.Login()
//附加功能,记录请求时间上报
endTime := time.Now()
new(MetricCollector).record("Login", endTime.Sub(startTime))
return res
}
func (p *UserProxy) Register() string {
//附加功能
startTime := time.Now()
//原始类业务逻辑
res := p.User.Register()
//附加功能,记录请求时间上报
endTime := time.Now()
new(MetricCollector).record("Register", endTime.Sub(startTime))
return res
}
// 信息上报类
type MetricCollector struct {
}
func (m *MetricCollector) record(info string, time time.Duration) {
}
// 实际应用
func testProxy() {
//u := &User{}
//原始类切换为代理类
u := &UserProxy{
User: &User{},
}
u.Login()
u.Register()
}
使用场景:
代理模式常用在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志。我们将这些附加功能与业务功能解耦,放到代理类统一处理,让程序员只需要关注业务方面的开发。除此之外,代理模式还可以用在 RPC、缓存等应用场景中