XingPiaoLiang's

Back

代理模式#

代理模式是一种结构型设计模式,能够提供某个对象的替代品或者占位符,代理对象内部封装着原对象,从而控制着原对象的访问,以此允许在将请求提交给原对象前后对结果进行处理。

问题示例#

假设此时有一个视频下载类VideoDownload,它提供了访问第三方接口的获得下载的视频的方法。但是此时它只是一个原子类,仅仅提供了这个方法,导致每次请求下载视频时,尽管请求的是同一个视频资源。还是会不断地重复相同的资源,这样会消耗大量系统资源和网络资源。同时网络延迟等问题,对用户也非常不友好。

问题解决#

代理模式指出,新建一个与原对象相同接口的代理类,当代理类收到客户端请求之后,首先会初始化该VideoDownload视频下载类,之后对客户端请求做了应有的处理之后,将所有的工作委派给原对象。

通过让代理对象实现与原类相同的接口,我们就可以无缝将其传递给任何一个使用该实际对象服务的客户端。

整体结构#

代码示例#

为了解决上述的视频下载问题,我们可以创建一个代理类VideoDownloadProxy,为避免资源消耗,我们为原有逻辑加上延迟初始化和缓存

type Video struct {
	title string
}

type VideoDownLoad interface {
	Download(string) Video
}

type BaseDownload struct{}

func (b *BaseDownload) Download(url string) Video {
	if url == "" {
		return Video{}
	}
	// mock the request
	fmt.Println("Get the Video from: ", url)
	time.Sleep(2 * time.Second)
	return Video{
		title: "A Thousand of words",
	}
}

type DownLoadProxy struct {
	DownloadSrv *BaseDownload
	VideoCache  map[string]Video
}

func (p *DownLoadProxy) Download(url string) Video {
	if url == "" {
		return Video{}
	}

	if v, ok := p.VideoCache[url]; ok {
		fmt.Println("Get the Video from the cache")
		return v
	}

	// initialize the origin class
	p.DownloadSrv = &BaseDownload{}

	// use the srv
	v := p.DownloadSrv.Download(url)
	p.VideoCache[url] = v
	return v
}
go

应用场景#

  • 虚拟代理(延迟初始化),如果存在着一个使用次数很少的重量级(消耗系统资源max)的类,可以使用代理模式虚拟初始化
  • 保护代理,可以通过代理模式在一定程度上保护原对象,防止恶意程序利用
  • 远程代理,调用远程服务对象时
  • 日志记录代理,需要记录调用原有对象的调用日志时
  • 缓存代理,需要缓存客户端请求结果。

对比总结#

  • 适配器为封装对象提供不同的接口,代理模式为对象提供相同的接口,装饰模式为对象提供加强的接口
  • 装饰和代理有着相似的结构, 但是其意图却非常不同。 这两个模式的构建都基于组合原则, 也就是说一个对象应该将部分工作委派给另一个对象。 两者之间的不同之处在于代理通常自行管理其服务对象的生命周期, 而装饰的生成则总是由客户端进行控制。
设计模式-结构型-代理
https://astro-pure.js.org/blog/proxy
Author erasernoob
Published at May 29, 2025
Comment seems to stuck. Try to refresh?✨