• 代理(Proxy)模式


      代理模式的类图如下所示:

          

         客户端想调用的是RealSubject,由于某种考虑或原因,只能直接访问到ProxySubject,再由ProxySubject去调用RealSubject,这就完成了一次代理的活动。

         代理模式的时序图如下:

         

          从上面可以看出,ProxySubject不仅可以完成对RealSubject的调用,在调用前后还可以完成一些事情,这就是代理模式的优点。

          代理模式按照使用的分类,可以分为以下几类:

          远程代理:为一个不同地址空间的对象提供一个局域代表对象。

          虚拟代理:根据需求创建一个资源消耗较大的对象,使得对象在使用时才被真正地使用。

          Copy-on-Write代理:虚拟代理的一种,把复制行为推迟到真正需要时再去执行。

          保护代理:控制对一个对象的访问,可以对不同用户提供不同权限。

          Cache代理:为某一目标的操作结果提供临时的存储空间,使得多个客户端可以共享这些结果。

          同步化代理:使得多个用户同时使用一个目标而没有冲突。

          智能引用代理:引用一个对象时提供一些额外的操作,如记录被调用的次数等。

         Java类库中有三个类直接支持代理模式:Proxy,InvocationHandler和Method。

         下面是在List加上代理,在添加元素的前后打印一些信息。     

    public class VectorProxy implements InvocationHandler{
        private Object proxyobj;
        public VectorProxy(Object obj){
            proxyobj = obj;
        }
    
    	public static Object factory(Object obj){
    		Class cls = obj.getClass();
            return Proxy.newProxyInstance( cls.getClassLoader(),
                cls.getInterfaces(),
                new VectorProxy(obj) );
        }
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
    		System.out.println("before calling " + method);
    
            if (args != null){
    			for (int i=0; i<args.length; i++){
                    System.out.println(args[i] + "");
                }
    		}
    
            Object o = method.invoke(proxyobj, args);
    
    		System.out.println("after calling " + method);
    
            return o;
        }
    
        public static void main(String[] args){
    		List v = null;
            v = (List) factory(new Vector(10));
            v.add("New");
            v.add("York");
        }
    }
    

      打印出的信息如下:

    before calling public abstract boolean java.util.List.add(java.lang.Object)
    New
    after calling public abstract boolean java.util.List.add(java.lang.Object)
    before calling public abstract boolean java.util.List.add(java.lang.Object)
    York
    after calling public abstract boolean java.util.List.add(java.lang.Object)
    

      

          一个网站可以为顾客提供股票的持有情况,从而判断是否是大量收购或抛售的情况,这是信息是很有用的,该网站属于计费网站。这里有两种情形是能使用代理模式的,一是对客户的身份进行检查,第二是对用户的使用情况进行统计,方便计费。

          上面提到的代理模式的种类,这里就可以对应上保护代理和智能引用代理两种。

           

         负责身份验证和查询次数记录功能类应该是分开处理,对应与上面类图中的AccessValidator和UsageLogger,统一于Proxy中进行调用。

         

        代理类Proxy 的示例代码为:   

    public class Proxy implements Searcher {    
        private RealSearcher searcher;
        private UsageLogger usageLogger;    
        private AccessValidator accessValidator;
    
        public Proxy(){
          searcher = new RealSearcher();
        }
    
        public String doSearch(String userId, String keyValue){
            if (checkAccess(userId)){
              String result = searcher.doSearch(null, keyValue);
                logUsage(userId);
            return result;
            }
            else{
                return null;
            }
        }
    
        private boolean checkAccess(String userId){
          accessValidator = new AccessValidator();
            return accessValidator.vaidateUser(userId);
        }
    
        private void logUsage(String userId){
          UsageLogger logger = new UsageLogger();
            logger.setUserId(userId);
            logger.save();
        }
    }

      负责身份校验的AccessValidator的示例代码:      

    public class AccessValidator{
        public boolean vaidateUser(String userId){
            if (userId.equals("Admin")){
                return true;
            }
            else{
                return false;
            }
        }
    }

      负责查询次数记录的UsageLogger的示例代码:

    public class UsageLogger{
        private String userId;
        public void setUserId(String userId){
            this.userId = userId;
        }
    
        public void save(){
            String sql = "INSERT INTO USAGE_TABLE (user_id) " +
                " VALUES(" + userId + ")";
            //execute this SQL statement
        }
    
        public void save(String userId){
            this.userId = userId;
            save();
        }
        
    }
    

      实际的查询处理类RealSearcher的示例代码:

    class RealSearcher implements Searcher{
        public RealSearcher(){
        }
    
        public String doSearch(String userId, String keyValue){
            String sql = "SELECT * FROM data_table WHERE key_col = '" + keyValue + "'";
    
            //execute this SQL Statement and concatenate a result string
            return "result set";
        }
    }
    

      

      系统加载一个较为耗时的模块时,首先显示“正在加载”的信息,同时在加载模块,模块加载完后去掉加载信息。这里可以使用代理模式。

         加载图片时,先加载一个分辨率较低的图片,等到真正的图片加载完后再进行显示,也可以使用代理模式去实现。

        

  • 相关阅读:
    cocos2d-x C++ 判断当前平台宏定义大全
    cocos2d-x JS 纯代码加载播放plist与png动画
    cocos2d-x JS 加载播放Studio帧动画的两种方法
    iOS开发小技巧总结
    cocos2d-x C++ (Android)集成第三方微信分享
    cocos2d-x C++ (iOS)集成第三方微信分享
    cocos2d-x JS 获取当前系统时间(解决屏幕双击点击事件)
    (已解决) eclipse提示报错"serializing cdt project settings"解决方案
    cocos2dx
    cocos2d-X JS 获取cocostudio中的UI组件
  • 原文地址:https://www.cnblogs.com/lnlvinso/p/3947963.html
Copyright © 2020-2023  润新知