代理模式

1,856 阅读3分钟

代理模式是结构型模式。结构型模式主要总结了一些类或对象组合在一起的经典结构,这些经典的结构可以解决特定应用场景的问题

原理和实现:

在不改变原始类(或叫被代理类)的情况下,通过引入代理类来给原始类附加功能。一般情况下,我们让代理类和原始类实现同样的接口。但是,如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的。在这种情况下,我们可以通过让代理类继承原始类的方法来实现代理模式

上面的这句话就说出来代理模式的两种应用,第一种是代理类和原始类都基于接口实现,这样实际应用的时候,只需要修改赋值给接口的类型由原始类改为代理类,代码改动比较小;还有一种是原始类是第三方,无法修改,无法基于接口实现,所以使用组合(或者说是继承)的方式让代理类继承原始类,但是这样代码改动比较大,所有用到原始类的地方都要替换成代理类

第一种基于接口实现如下

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、缓存等应用场景中