结构型之代理模式

结构型

结构型模式主要总结了一些类或对象组合在一起的经典结构,这些经典的结构可以解决特定应用场景的问题。结构型模式包括:代理模式、桥接模式、装饰器模式、适配器模式、门面模式、组合模式、享元模式。

代理模式

代理模式在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是它跟装饰器模式最大的不同。一般情况下,我们让代理类和原始类实现同样的接口。但是,如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的。在这种情况下,我们可以通过让代理类继承原始类的方法来实现代理模式。
在这里插入图片描述
由于Golangjava的差异性,我们无法比较方便的利用反射实现动态代理,所以这里主要介绍静态代理

静态代理

例一

package proxy

import (
	"log"
	"time"
)

// IUser IUser
type IUser interface {
	Login(username, password string) error
}

// User 用户
type User struct {
}

// Login 用户登录
func (u *User) Login(username, password string) error {
	// 不实现细节
	return nil
}

// UserProxy 代理类,包含了原始类,并且和原始类实现了相同接口IUser
type UserProxy struct {
	user *User
}

// NewUserProxy NewUserProxy
func NewUserProxy(user *User) *UserProxy {
	return &UserProxy{
		user: user,
	}
}

// Login 登录,和 user 实现相同的接口
func (p *UserProxy) Login(username, password string) error {
	// before 这里可能会有一些统计的逻辑
	start := time.Now()

	// 这里是原有的业务逻辑
	if err := p.user.Login(username, password); err != nil {
		return err
	}

	// after 这里可能也有一些监控统计的逻辑
	log.Printf("user login cost time: %s", time.Now().Sub(start))

	return nil
}

例二

// 代理模式:代理模式在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是它跟装饰器模式最大的不同。
package main

// 场景举例:为 UserController 的 register 和 login 方法增加 metrics 打点

// 用户类,业务中用到的实体类
type UserVo struct{}

// 抽象接口,在业务代码中使用接口
type IUserController interface {
	login(telephone, password string) UserVo
	register(telephone, password string) UserVo
}

// UserController 类,被代理类,处理实际业务
type UserController struct{}

func (uc UserController) register(telephone, password string) UserVo {
	// ... register 逻辑 ...
	return UserVo{}
}

func (uc UserController) login(telephone, password string) UserVo {
	// ... login 逻辑 ...
	return UserVo{}
}

// metrics 类
type MetricsCollector struct{}

func (ms MetricsCollector) recordRequest() {}

func NewMetricsCollector() MetricsCollector {
	return MetricsCollector{}
}

// UserController的代理类,组合其他类对UserController类相关功能增强
type UserControllerProxy struct {
	userController   UserController
	metricsCollector MetricsCollector
}

func NewUserControllerProxy(userController UserController) UserControllerProxy {
	return UserControllerProxy{
		userController:   userController,
		metricsCollector: NewMetricsCollector(),
	}
}

// 需要和被代理类实现相同接口,这样才可以把代理类传给接口,然后使用接口,感觉上就像和在使用被代理类一样,实际已经对功能进行了增强
func (ucp UserControllerProxy) register(telephone, password string) UserVo {
	userVo := ucp.userController.register(telephone, password)
	ucp.metricsCollector.recordRequest()
	return userVo
}

func (ucp UserControllerProxy) login(telephone, password string) UserVo {
	userVo := ucp.userController.login(telephone, password)
	ucp.metricsCollector.recordRequest()
	return userVo
}

应用场景

代理模式常用在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志。我们将这些附加功能与业务功能解耦,放到代理类统一处理,让程序员只需要关注业务方面的开发。除此之外,代理模式还可以用在 RPC、缓存等应用场景中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值