代理模式
代理模式是一种结构型设计模式, 让你能够提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。
结构
代理模式的结构比较简单。为了让客户端能够一致地对待真实对象和代理对象,我们引入了抽象层。
需求&差代码
在你的游戏里,你负责开发一个联机的类塞尔达相簿系统。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W7ge9P23-1676261446330)(null)]
这些图片都是存在服务端的,现在要求你开发一个ImgDownloader,把接口给UI制作人员以供他调用。
public class ImgDownloader{
public bool DownLoadImg(int id){
//把id发给后端,等后端把文件流传回来,再把文件流写入相册
return true;
}
}
你三下五除二写好了,接口也给出去了,测试都测好了。
结果服务端找过来了。
服务端:“欸大哥,你这玩意儿性能开销有点大啊。玩家每次点击图片你都给下载,我服务器都要被搞挂了。你加个缓存机制吧”
你:”有道理,策划怎么也不提要做个缓存呢?考虑地太浅啦!都怪策划“
服务端:”对对对,都怪策划,你给加个缓存吧“
于是你准备加个缓存字典,大概是这样的。
public class ImgDownloader
{
private Dictionary<int, bool> downloadCache;
private ImgDownloader()
{
downloadCache = new Dictionary<int, bool>();
}
/// <summary>
/// 下载图片
/// </summary>
/// <param name="id">图片id</param>
/// <returns></returns>
public bool DownLoadImg(int id)
{
bool downloaded = false;
downloadCache.TryGetValue(id, out downloaded);
if (downloaded)
{
// 已经下载过,无需重复下载
return false;
}
//把id发给后端,等后端把文件流传回来,再把文件流写入相册
return true;
}
}
这时候测试不乐意了。
测试:“大哥,我都测好了,你全部重新改一轮我得全部重新测一遍啊”
你:“我只是加个缓存,其他地方都不改的你不测也行”
测试:“我不信,上次你说你就改个配置,结果不小心动了行别的代码,线上出了P0 BUG我还被领导批了呢”
你:“我想想啊,我接口都不改,用代理模式引入一个缓存代理做缓存用,这样下载相关的逻辑肯定不会被改到了”
好代码(用代理模式实现需求)
摘录部分代码:
public class DownloadCacher : IDownloader
{
private Dictionary<int, bool> _cache;
private ImgDownloader _imgDownloader;
public DownloadCacher()
{
_imgDownloader = new ImgDownloader();
_cache = new Dictionary<int, bool>();
}
public bool DownloadImg(int id)
{
bool downloaded = false;
_cache.TryGetValue(id, out downloaded);
if (!downloaded)
{
return _imgDownloader.DownloadImg(id);
}
else
{
return false;
}
}
}
调用:
// 示例代码
IDownloader downloader = new DownloadCacher();
downloader.DownloadImg(1);
常用例子
-
虚拟代理—延迟初始化
如果你有一个偶尔使用的重量级服务对象, 一直保持该对象运行会消耗系统资源时, 可使用代理模式。
-
缓存代理。适用于需要缓存客户请求结果并对缓存生命周期进行管理时, 特别是当返回结果的体积非常大时。
例如一个视频下载类,正常它没有缓存功能。我们添加一个公共接口,再引入一个代理类,在代理里实现缓存功能
-
日志代理。
适用于需要保存请求记录时。
-
远程代理。
本地执行远程代码。
-
智能引用代理。
代理可以将引用记录在案,提供一些额外操作如是否仍在运行/是否被修改了/是否可复用/被调用次数。
-
保护代理——访问控制
优点
-
开闭原则
不修改服务或客户端就能创建新代理
源码
完整代码已上传至nickpansh/Unity-Design-Pattern | GitHub