• 结构类模式(七):代理(Proxy)


    定义

    为其他对象提供一种代理以控制对这个对象的访问。

    代理模式也叫做委托模式,它是一项基本设计技巧。许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式,而且在日常的应用中,代理模式可以提供非常好的访问控制。

    代理类负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。

    基本上可以理解为:代理类持有实际操作对象的引用,通过公开方法将这些引用的方法提供给其它类调用。

    和其它模式的区别

    1. 和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理迷失不能改变所代理类的接口。
    2. 和装饰模式的区别:装饰模式为了增强功能,而代理模式是为了加以控制。

    UML

    优点

    1. 真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰。
    2. 具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。

    缺点

    1. 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
    2. 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

    应用场景

    远程代理

    为一个对象在不同的地址空间提供局部代表。

    虚代理

    根据需要创建开销很大的对象。比如浏览网页时,图片可以使用代理先按宽高进行占位,下载好再进行显示。

    保护代理

    控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。

    智能指针

    取代了简单的指针,它在访问对象时执行一些附加操作。

    它的典型用途包括:

    1. 对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它。
    2. 当第一次引用一个持久对象时,将它装入内存。
    3. 在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。

    示例

    游戏玩家(被代练对象)和游戏代练者(代理对象)的示例,其中如果游戏玩家升级则游戏代练则要进行收费。

    C++

    C#

      1 using System;
      2 
      3 namespace DesignPattern
      4 {
      5     class Program
      6     {
      7         static void Main(string[] args)
      8         {
      9             //李雷自己打游戏
     10             GamePlayer liLei = new GamePlayer("李雷");
     11             liLei.Login();
     12             liLei.KillMonster();
     13             liLei.Upgrade();
     14 
     15             Console.WriteLine();
     16 
     17             //李雷花钱请游戏代练帮其升级
     18             Leveling leveling = new Leveling(liLei);
     19             leveling.Login();
     20             leveling.KillMonster();
     21             leveling.Upgrade();
     22 
     23             Console.Read();
     24         }
     25     }
     26 
     27     /// <summary>
     28     /// 游戏玩家接口.
     29     /// </summary>
     30     public interface IGamePlayer
     31     {
     32         /// <summary>
     33         /// 登录.
     34         /// </summary>
     35         void Login();
     36 
     37         /// <summary>
     38         /// 打怪.
     39         /// </summary>
     40         void KillMonster();
     41 
     42         /// <summary>
     43         /// 升级.
     44         /// </summary>
     45         void Upgrade();
     46     }
     47 
     48     /// <summary>
     49     /// 玩家类.
     50     /// </summary>
     51     public class GamePlayer : IGamePlayer
     52     {
     53         private string _name;
     54 
     55         public GamePlayer(string name)
     56         {
     57             _name = name;
     58         }
     59 
     60         public void Login()
     61         {
     62             Console.WriteLine("玩家"" + _name + ""登录游戏。");
     63         }
     64 
     65         public void KillMonster()
     66         {
     67             Console.WriteLine("玩家"" + _name + ""开始打怪。");
     68         }
     69 
     70         public void Upgrade()
     71         {
     72             Console.WriteLine("玩家"" + _name + ""等级提升一级。");
     73         }
     74     }
     75 
     76     /// <summary>
     77     /// 游戏代练类.
     78     /// </summary>
     79     public class Leveling : IGamePlayer
     80     {
     81         private GamePlayer _gamePlayer;
     82 
     83         public Leveling(GamePlayer gamePlayer)
     84         {
     85             _gamePlayer = gamePlayer;
     86         }
     87 
     88         public void Login()
     89         {
     90             _gamePlayer.Login();
     91         }
     92 
     93         public void KillMonster()
     94         {
     95             _gamePlayer.KillMonster();
     96         }
     97 
     98         public void Upgrade()
     99         {
    100             _gamePlayer.Upgrade();
    101 
    102             Console.WriteLine("游戏代练者收费。");
    103         }
    104     }
    105 }
    View Code

    Java

    Java的示例使用延迟代理和动态代理查询天气的例子。

      1 public class Main
      2 {
      3     public static void main(String[] args)
      4     {
      5         //不使用代理
      6         IWeather weather1 = new ChinaWeather();
      7         System.out.println(weather1.getWeatherByCity("上海"));
      8         
      9         //延迟代理
     10         IWeather weather2 = new ChinaWeatherDelayProxy();
     11         System.out.println(weather2.getWeatherByCity("北京"));
     12         
     13         //动态代理
     14         IWeather weather3 = new WeatherDynamicProxy(new InternationalWeather());
     15         System.out.println(weather3.getWeatherByCity("北京"));
     16     }
     17 
     18     /**
     19      * 天气查询接口
     20      */
     21     public interface IWeather
     22     {
     23         /**
     24          * 获取指定城市的天气情况
     25          */
     26         String getWeatherByCity(String city);
     27         
     28         /**
     29          * 请求查询
     30          */
     31         void request();
     32     }
     33 
     34     /**
     35      * 使用中国的天气服务器查询天气情况,只能查询到中国的天气
     36      */
     37     public static class ChinaWeather implements IWeather
     38     {
     39         public ChinaWeather()
     40         {
     41             this.request();
     42         }
     43         
     44         @Override
     45         public String getWeatherByCity(String city)
     46         {
     47             if(city.equals("北京"))
     48             {
     49                 return "晴 28度 PM2.5 20";
     50             }
     51             if(city.equals("上海"))
     52             {
     53                 return "晴 33度 PM2.5 10";
     54             }
     55             return "未知";
     56         }
     57 
     58         @Override
     59         public void request()
     60         {
     61             System.out.println("请求中国的天气服务器,解析其格式得到信息");
     62         }
     63     }
     64 
     65     /**
     66      * 使用国际的天气服务器查询天气情况,当然也可以查询到中国的天气了
     67      */
     68     public static class InternationalWeather implements IWeather
     69     {
     70         public InternationalWeather()
     71         {
     72             this.request();
     73         }
     74         
     75         @Override
     76         public String getWeatherByCity(String city)
     77         {
     78             if(city.equals("北京"))
     79             {
     80                 return "晴 29度 PM2.5 500+";
     81             }
     82             if(city.equals("上海"))
     83             {
     84                 return "晴 32度 PM2.5 500+";
     85             }
     86             return "未知";
     87         }
     88 
     89         @Override
     90         public void request()
     91         {
     92             System.out.println("请求国际的天气服务器,解析其格式得到信息");
     93         }
     94     }
     95 
     96     /**
     97      * 延迟代理
     98      */
     99     public static class ChinaWeatherDelayProxy implements IWeather
    100     {
    101         private IWeather weather;
    102         
    103         private IWeather getWeather()
    104         {
    105             if(weather == null)
    106             {
    107                 weather = new ChinaWeather();
    108             }
    109             return weather;
    110         }
    111         
    112         @Override
    113         public String getWeatherByCity(String city)
    114         {
    115             return getWeather().getWeatherByCity(city);
    116         }
    117 
    118         @Override
    119         public void request()
    120         {
    121             getWeather().request();
    122         }
    123     }
    124 
    125     /**
    126      * 动态代理
    127      */
    128     public static class WeatherDynamicProxy implements IWeather
    129     {
    130         private IWeather weather;
    131         
    132         public WeatherDynamicProxy(IWeather weather)
    133         {
    134             this.weather = weather;
    135         }
    136 
    137         @Override
    138         public String getWeatherByCity(String city)
    139         {
    140             return weather.getWeatherByCity(city);
    141         }
    142 
    143         @Override
    144         public void request()
    145         {
    146             weather.request();
    147         }
    148     }
    149 }
    View Code

    AS3

    我的经验总结

    在PureMVC框架中,其Model层使用了Proxy的设计模式。

    我们先看看Model层的主要功能:

    1. 保存程序数据;
    2. 远程消息发送及请求。

    在我们的游戏中,分别存在UserData及SocketConnection这两个对象,其中UserData用来存储用户数据,SocketConnection用来处理所有远程消息的接收和发送,而每个模块的Proxy都是对这两个对象的代理,其提供该模块需要的数据和操作接口给该模块,比如技能模块中,Proxy会提供技能相关的数据和协议给到该模块的View层。代理类为模块提供了屏蔽不需要的接口的功能。

    然而在PureMVC的升级版框架RobotLegs中,其定义的是MVCS的框架,Model层直接设计为Model+Services的组合,没有使用代理模式,由于没有代理模式,所以中介类中就不是直接操作代理类,而一般情况是通过发送Command,在Command中进行处理。

  • 相关阅读:
    LeetCode:Remove Duplicates from Sorted List
    LeetCode:Remove Nth Node From End of List
    LeetCode:Delete Node in a Linked List
    LeetCode:Rotate Image
    LeetCode:Anagrams(字母颠倒)
    LeetCode:Single NumberⅡ
    LeetCode:Single Number
    LeetCode:Longest Common Prefix
    bzoj1025
    bzoj1024
  • 原文地址:https://www.cnblogs.com/hammerc/p/4743796.html
Copyright © 2020-2023  润新知