结构型模式就是通过多个类和对象进行组合得到复杂结构的类,一般使用继承或者成员变量引用的形式来实现。
基本介绍
代理设计模式(Proxy Design Pattern),为其它对象提供一种代理以控制这个对象的访问和扩展。换言之就是给某个对象提供一个代理,并由代理控制原对象的引用。
何时使用:想在访问一个类时做一些控制。
如何解决:增加中间层。
应用场景
- Windows里面的快捷方式
- 西游记中,猪八戒去找高翠兰,结果是孙悟空变的,可以这样理解:高翠兰的外貌是一个基类,高翠兰继承自这个基类,孙悟空也继承自这个外貌的基类,但猪八戒并不知道他接触的高翠兰是孙悟空,此时孙悟空就是高翠兰的代理
- 我们买火车票不一定要去车站,可以去代售点,而代售点就是代理,也能够售票
- 一张支票或者银行存单是银行账户的资金代理,我们可以凭借存单或者支票也能够在市场中进行买卖,这里典型的一个应用就是通承兑
我们点外卖,外卖员就是我们的代理,我们不需要自己去店取餐,外卖员替我们取餐
结构
通过上图我们会发现代理模式有三个角色:抽象主题角色(Subject): 通过接口或抽象类声明真实主题和代理对象实现的业务方法,这样一来凡是使用真实主题的任何地方都可以使用代理
- 真实主题角色(RealSubject): 实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
代理主题角色(Proxy):代理主题角色内部包含了真实主题角色的引用,从而可以操作真实主题对象,代理主题角色在需要用到的时候创建真实的主题对象。
为什么使用代理
简单来说:在不改变原始类的情况下,通过引入代理类来给原始类附加功能。一般情况下,我们让代理类继承实现原始类同样的接口。但如果原始类并没有定义接口,而且原始类代码并不是我们开发维护的,这种情况下,我们可以让代理类继承原始类的方法来实现代理类。
当无法或不想直接引用某个对象或访问某个对象存在困难时,可以通过代理对象来间接访问。使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。
例如搜索内容,第一次搜索后利用缓存代理对本次搜索结果进行缓存,第二次搜索从缓存中获取就快多了。
再例如游戏中初始化多个Manager,可以不用开始时立马创建;利用代理管理Manager,我们启动时启动各种代理,当真正要用到某个Manager时再进行实例,这样是懒加载的模式。常用代理类型
防火墙代理
控制网络资源的访问,保护主题免于”坏客户”的侵害。- 智能引用代理
当主题被引用时,进行额外的动作,例如计算一个对象的被引用次数。 - 缓存代理
为开销大的运算结果提供暂时存储,它也允许多个客户共享结果,以减少计算或网络延迟。 - 同步代理
在多线程的情况下为主题提供安全的访问。 - 复杂隐藏代理
用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也称外观代理,复杂隐藏代理和外观模式是不一样的,因为代理需要实际控制访问,而外观模式只提供另一组接口。 写入时复制代理
用来控制对象的复制,方法是延时对象的复制,直到客户真的需要为止。这是虚拟代理的变体。代理模式优劣
优点
降低耦合度,代理模式能够将调用者与被调用者做一层对象隔离,在一定程度上降低复杂度
- 扩展性好,不需要修改被代理类即可实现新增功能,符合开闭原则
- 职责清晰,我们可以细分代理权限,比如安全代理、缓存代理等等
-
缺点
在被代理类之间增加了一个代理对象,会造成请求处理的速度变慢
-
基础实现
在代码中,一般代理会被理解为代码增强,实际上就是在原代码逻辑前后增加一些代码逻辑,而使调用者无感知。
根据代理的创建时期,代理模式分为静态代理和动态代理。 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。
- 动态:在程序运行时,运用反射机制动态创建而成
//抽象主题
interface Subject
{
public void Request();
}
//真实主题
public class RealSubject : Subject
{
public void Request()
{
Debug.Log("访问真实主题");
}
}
//代理
public class Proxy : Subject
{
private RealSubject realSubject;
public void Request()
{
if (realSubject == null)
{
realSubject = new RealSubject();
}
preRequest();
realSubject.Request();
postRequest();
}
public void preRequest()
{
Debug.Log("访问真实主题之前的预处理");
}
public void postRequest()
{
Debug.Log("访问真实主题之后的后续处理");
}
}
//执行
public class ProxyTest : MonoBehaviour
{
void Start()
{
Proxy proxy = new Proxy();
proxy.Request();
}
}
//结果:
//访问真实主题之前的预处理
//访问真实主题
//访问真实主题之后的后续处理