写在前面:

代理模式的内部原理,作用及远程代理的实现在上一篇博文中都做了详细解释,本文只是对其内容的补充,介绍其它代理

一.虚拟代理

首先,明确虚拟代理的作用:在巨大对象被真正创建出来之前,用虚拟代理来代替巨大对象(保证了巨大对象在需要的时候才被创建,避免资源浪费)

虚拟代理我们可能经常在用,只是不认识它而已,比如:

我们的程序中可能存在密集的计算或者从服务器取得大量数据这样耗时耗资源的操作,一般都会先显示默认信息,或者显示动画表示我们的程序还在努力工作,在操作完成之后显示获得的信息

其中就用到了虚拟代理的思想,只是虚拟代理把等待操作完成期间的工作全部分离出来封装到了一个虚拟代理对象里面,与客户直接交互的是虚拟代理而不是实际做事情的对象

虚拟代理接到客户请求后做了这样几件事情:

  1. 如果实际对象不存在(尚未创建或者尚未创建完成)则记录客户请求,显示默认信息,等到实际对象创建完成之后把请求传递给实际对象
  2. 如果实际对象已经存在,则直接把客户请求委托给实际对象
  3. 在实际对象没有传回操作结果之前,代理对象负责显示默认信息(或者做默认处理)
  4. 得到操作结果后直接传递给客户(没错,代理的任务就是“交”与“接”)

既然是代理,那么就要伪装成实际对象,不能让客户发觉代理的存在,所以虚拟代理的类图是这样的:

Client持有一个虚拟代理对象Proxy,Proxy持有一个具体服务对象MyService

而更重要的是:虚拟代理Proxy与具体服务MyService都扩展自Service接口,所以代理与实际对象具有相同的行为,客户不会发觉Proxy的存在

二.保护代理

保护代理扮演着经纪人的角色(不是所有人都可以联系我背后的明星,你们只能联系我,在我确定你不是坏人之后,才给你转接。。)

换句话说,保护代理为实际对象提供了访问控制,保证了只有合法的调用者才能得到服务

实现的话,类图和上面的虚拟代理完全一样,只是Proxy多了一项判断调用者权限的职责(发现什么了吗?我们好像可以把多个代理结合起来使用,当然这样的代理不再满足类的单一责任原则,不过没关系,我们完全可以创建一个代理的代理来管理一系列代理。。)

其实Java的API提供了对代理模式的支持(动态代理)

Java提供的动态代理的动态体现在Proxy代理类(没错,是类,而不是对象)是在运行时才被创建的,我们不能直接修改Proxy的内部实现,但我们可以通过InvocationHandler来告诉Proxy应该怎么做

采用动态代理来实现保护代理的基本思路是:创建多个代理,不同的代理表示不同权限的调用者对应的服务

那么让我们来设计一个情景,尝试用动态代理实现保护代理:

博文点赞机制:可以赞别人的博文,不能赞自己的博文,但博主和游客都可以看到被赞数目

情景比较简单,不过足够说明问题了,下面开始模拟实现

-------

首先要有BlogUser:

package ProxyPattern.ProtectionProxy;

/**
* 定义博客用户接口
* @author ayqy
*/
public interface BlogUser {
public void support();
public int getSupportCount();
}

还要有ConcreteUser,其实现过程比较简单,不在此展开

下面开始创建动态代理,这里有两种权限,博主与游客,所以我们至少需要两个不同的动态代理

AuthorHandler:

package ProxyPattern.ProtectionProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; /**
* 实现为作者服务的InvocationHandler
* @author ayqy
*/
public class AuthorHandler implements InvocationHandler{
BlogUser user; public AuthorHandler(BlogUser user){
this.user = user;
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws IllegalAccessException {//声明非法访问异常
try {
/*如果博主想要查看被赞数目,则委托给调用者user实现具体操作*/
if(method.getName().equals("getSupportCount")){
return method.invoke(user, args);
}
/*如果博主要给自己点赞,则抛出异常表示拒绝*/
if(method.getName().equals("support")){
throw new IllegalAccessException();
}
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} return null;//如果调用其它方法,直接无视
} }

与此类似,还需要实现VisitorHandler

有了多个代理,我们还需要实现代理的代理,也就是保护代理(视调用者权限返回一个对应的动态代理)

ProtectionProxy:

package ProxyPattern.ProtectionProxy;

import java.lang.reflect.Proxy;

/**
* 实现保护代理
* @author ayqy
*/
public class ProtectionProxy {
/**
* @param user 调用者
* @return 作者对应的代理
*/
public BlogUser getAuthorProxy(BlogUser user){
return (BlogUser)Proxy.newProxyInstance(user.getClass().getClassLoader()
, user.getClass().getInterfaces()
, new AuthorHandler(user));
} /**
* @param user 调用者
* @return 游客对应的代理
*/
public BlogUser getVisitorProxy(BlogUser user){
return (BlogUser)Proxy.newProxyInstance(user.getClass().getClassLoader()
, user.getClass().getInterfaces()
, new VisitorHandler(user));
} /*在此处插入生成其它代理的方法*/
}

有了这些就足够了,做一个简单的测试:

package ProxyPattern.ProtectionProxy;

/**
* 实现测试类
* @author ayqy
*/
public class Test {
public static void main(String[] args){
//创建保护代理
ProtectionProxy proxy = new ProtectionProxy(); System.out.println("博主部分:");
//创建博主对应的代理
BlogUser authorProxy = proxy.getAuthorProxy(new ConcreteUser());
System.out.println("博主要查看被赞总数");
System.out.println("被赞 " + authorProxy.getSupportCount() + " 次");
//博主要给自己点赞
System.out.println("博主要给自己点赞");
try{
authorProxy.support();
}catch(Exception e){
System.out.println("点赞失败,无法给自己点赞");
}
System.out.println("自赞之后,被赞 " + authorProxy.getSupportCount() + " 次"); System.out.println("\n游客部分:");
//创建游客对应的代理
BlogUser vistorProxy = proxy.getVisitorProxy(new ConcreteUser());
System.out.println("游客要查看被赞总数");
System.out.println("被赞 " + vistorProxy.getSupportCount() + " 次");
//博主要给自己点赞
System.out.println("游客要给博主点赞");
try{
vistorProxy.support();
}catch(Exception e){
System.out.println("点赞失败,原因未知");
}
System.out.println("点赞之后,被赞 " + vistorProxy.getSupportCount() + " 次");
}
}

测试结果:

三.其它代理

代理模式应用很广泛,无法一一列举所有代理,在此简单介绍几种常见的代理:

代理名称 作用
防火墙代理 控制网络资源的访问,保护主题免于“坏客户”的侵害
智能引用代理 当主题被引用时,进行额外的动作,比如计算一个对象被引用的次数
缓存代理 为开销大的运算结果提供暂时存储,也允许多个客户共享结果,以减少计算或网络延迟
同步代理 在多线程的情况下为主题提供安全的访问
复杂隐藏代理(外观代理) 用来隐藏一个类的复杂集合的复杂度,并进行访问控制(比外观模式功能更强大)
写入时复制代理 用来控制对象的复制,方法是延迟对象的复制,直到真正需要复制为止(与虚拟代理类似)

当然,只要理解了最原始的远程代理,遇到这些代理就都很容易理解。。

设计模式之代理模式(Proxy Pattern)_补充篇的更多相关文章

  1. 乐在其中设计模式(C#) - 代理模式(Proxy Pattern)

    原文:乐在其中设计模式(C#) - 代理模式(Proxy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 代理模式(Proxy Pattern) 作者:webabcd 介绍 为 ...

  2. 二十四种设计模式:代理模式(Proxy Pattern)

    代理模式(Proxy Pattern) 介绍为其他对象提供一个代理以控制对这个对象的访问. 示例有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对 ...

  3. c#设计模式之代理模式(Proxy Pattern)

    引言 代理这个词语,大家在现实世界已经频繁的接触过,例如火车站代理售票点,因为这些代理售票点的存在,我们不必要去火车站的售票处就可以查询或者取到火车票.代理点本身是没有能力生产车票的,我们在代理处享受 ...

  4. 乐在其中设计模式(C#) - 代理模式(Proxy Pattern)【转】

    介绍 为其他对象提供一个代理以控制对这个对象的访问. 示例 有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对象的访问. MessageModel ...

  5. 设计模式系列之代理模式(Proxy Pattern)——对象的间接访问

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  6. 设计模式 - 代理模式(proxy pattern) 未使用代理模式 具体解释

    代理模式(proxy pattern) 未使用代理模式 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 部分代码參考: http://blog.csdn. ...

  7. 代理模式(Proxy pattern)

    代理模式(proxy pattern):作用:为其他对象提供一种代理,以控制对这个对象的访问.代理对象在客户端对象和目标对象之间起中介的作用. 代理模式涉及到的角色: 抽象角色:声明真实对象和代理对象 ...

  8. 设计模式——代理模式(Proxy Pattern)

    代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问. UML图: 模型设计: Subject类: package com.cnblog.clarck; /** * Subject 类 ...

  9. 大熊君说说JS与设计模式之------代理模式Proxy

    一,总体概要 1,笔者浅谈 当我们浏览网页时,网页中的图片有时不会立即展示出来,这就是通过虚拟代理来替代了真实的图片,而代理存储了真实图片的路径和尺寸,这就是代理方式的一种. 代理模式是比较有用途的一 ...

  10. 13.代理模式(Proxy Pattern)

    using System; namespace Test { //抽象角色:声明真实对象和代理对象的共同接口. //代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象, //同时代理 ...

随机推荐

  1. flush(), clear(), save()的简单解释

    hibernate最新发布包的javadoc里对这三个方法的解释是: clear() :Completely clear the session.清空session,该清空操作只对于要保存的.删除的和 ...

  2. kwic--Java统计单词个数并按照顺序输出

    2016-07-02(随笔写作时间) 写了好久的程序了为了避免以后用到.......... 是一个统计单词个数,并按照个数从大到小输出的.输入文件名OK 了 单词是按照首字母排序的,,,里面用到映射等 ...

  3. Linux CentOS6.6 NFS服务的配置与安装

    一.简介 NFS(Network File System)即网络文件系统,是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源.在NFS的应用中,本地NFS的客 ...

  4. windows常用的cmd网络命令

    一.ping 它是用来检查网络是否通畅或者网络连接速度的命令.作为一个生活在网络上的管理员或者黑客来说,ping命令是第一个必须掌握的DOS命令,它所利用的原理是这样的:网络上的机器都有唯一确定的IP ...

  5. Nmap参数说明

    Nmap(Network Mapper)是一款开放源代码的网络探测和安全审核工具.它的设计目标是快速地扫描大型网络,不适应于单一主机.Nmap使用检测IP数据包来确定访问的主机.提供的服务.数据包的类 ...

  6. oracle导入导出dmp 解决exp-00011

    解决办法,批量修改Segment.1先查找所有数据表为空的表 select table_name from user_tables where NUM_ROWS=0; 2若查不出数据,是因为 NUM_ ...

  7. 数学整合 新(LUOGU)

    1.卡特兰数(P2532) 递推式:h(n)=C(2n,n)/(n+1) (n=0,1,2,...) 前十项(从零开始):1, 1, 2, 5, 14, 42, 132, 429, 1430, 486 ...

  8. 编译器C1001问题

    https://ask.csdn.net/questions/184495 http://blog.sina.com.cn/s/blog_7822ce750100szed.html

  9. linux c++连接mysql编译问题

  10. 类方法 isAssignableFrom、instanceof 和 asSubclass

    类方法 isAssignableFrom.instanceof 和 asSubclass Spring 框架 CollectionFactory 的 asEnumType 方法使用 "类.a ...