结构型模式就是通过多个类和对象进行组合得到复杂结构的类,一般使用继承或者成员变量引用的形式来实现。

基本介绍

代理设计模式(Proxy Design Pattern),为其它对象提供一种代理以控制这个对象的访问和扩展。换言之就是给某个对象提供一个代理,并由代理控制原对象的引用。
何时使用:想在访问一个类时做一些控制。
如何解决:增加中间层。

应用场景

  • Windows里面的快捷方式
  • 西游记中,猪八戒去找高翠兰,结果是孙悟空变的,可以这样理解:高翠兰的外貌是一个基类,高翠兰继承自这个基类,孙悟空也继承自这个外貌的基类,但猪八戒并不知道他接触的高翠兰是孙悟空,此时孙悟空就是高翠兰的代理
  • 我们买火车票不一定要去车站,可以去代售点,而代售点就是代理,也能够售票
  • 一张支票或者银行存单是银行账户的资金代理,我们可以凭借存单或者支票也能够在市场中进行买卖,这里典型的一个应用就是通承兑
  • 我们点外卖,外卖员就是我们的代理,我们不需要自己去店取餐,外卖员替我们取餐

    结构

    image.png
    通过上图我们会发现代理模式有三个角色:

  • 抽象主题角色(Subject): 通过接口或抽象类声明真实主题和代理对象实现的业务方法,这样一来凡是使用真实主题的任何地方都可以使用代理

  • 真实主题角色(RealSubject): 实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  • 代理主题角色(Proxy):代理主题角色内部包含了真实主题角色的引用,从而可以操作真实主题对象,代理主题角色在需要用到的时候创建真实的主题对象。

    为什么使用代理

    简单来说:在不改变原始类的情况下,通过引入代理类来给原始类附加功能。一般情况下,我们让代理类继承实现原始类同样的接口。但如果原始类并没有定义接口,而且原始类代码并不是我们开发维护的,这种情况下,我们可以让代理类继承原始类的方法来实现代理类。
    当无法或不想直接引用某个对象或访问某个对象存在困难时,可以通过代理对象来间接访问。使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。
    例如搜索内容,第一次搜索后利用缓存代理对本次搜索结果进行缓存,第二次搜索从缓存中获取就快多了。
    再例如游戏中初始化多个Manager,可以不用开始时立马创建;利用代理管理Manager,我们启动时启动各种代理,当真正要用到某个Manager时再进行实例,这样是懒加载的模式。

    常用代理类型

  • 防火墙代理
    控制网络资源的访问,保护主题免于”坏客户”的侵害。

  • 智能引用代理
    当主题被引用时,进行额外的动作,例如计算一个对象的被引用次数。
  • 缓存代理
    为开销大的运算结果提供暂时存储,它也允许多个客户共享结果,以减少计算或网络延迟。
  • 同步代理
    在多线程的情况下为主题提供安全的访问。
  • 复杂隐藏代理
    用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也称外观代理,复杂隐藏代理和外观模式是不一样的,因为代理需要实际控制访问,而外观模式只提供另一组接口。
  • 写入时复制代理
    用来控制对象的复制,方法是延时对象的复制,直到客户真的需要为止。这是虚拟代理的变体。

    代理模式优劣

    优点

  • 降低耦合度,代理模式能够将调用者与被调用者做一层对象隔离,在一定程度上降低复杂度

  • 扩展性好,不需要修改被代理类即可实现新增功能,符合开闭原则
  • 职责清晰,我们可以细分代理权限,比如安全代理、缓存代理等等
  • 保护被代理类,调用者不可直接操作被代理类

    缺点

  • 在被代理类之间增加了一个代理对象,会造成请求处理的速度变慢

  • 实现代理类也需要额外的工作,从而增加系统的真实复杂度

    基础实现

    在代码中,一般代理会被理解为代码增强,实际上就是在原代码逻辑前后增加一些代码逻辑,而使调用者无感知。
    根据代理的创建时期,代理模式分为静态代理和动态代理。

  • 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。

  • 动态:在程序运行时,运用反射机制动态创建而成
    1. //抽象主题
    2. interface Subject
    3. {
    4. public void Request();
    5. }
    6. //真实主题
    7. public class RealSubject : Subject
    8. {
    9. public void Request()
    10. {
    11. Debug.Log("访问真实主题");
    12. }
    13. }
    14. //代理
    15. public class Proxy : Subject
    16. {
    17. private RealSubject realSubject;
    18. public void Request()
    19. {
    20. if (realSubject == null)
    21. {
    22. realSubject = new RealSubject();
    23. }
    24. preRequest();
    25. realSubject.Request();
    26. postRequest();
    27. }
    28. public void preRequest()
    29. {
    30. Debug.Log("访问真实主题之前的预处理");
    31. }
    32. public void postRequest()
    33. {
    34. Debug.Log("访问真实主题之后的后续处理");
    35. }
    36. }
    37. //执行
    38. public class ProxyTest : MonoBehaviour
    39. {
    40. void Start()
    41. {
    42. Proxy proxy = new Proxy();
    43. proxy.Request();
    44. }
    45. }
    46. //结果:
    47. //访问真实主题之前的预处理
    48. //访问真实主题
    49. //访问真实主题之后的后续处理