1、模式简介

代理模式的简介:

  为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,可以去掉功能服务或增加额外服务。

常见的代理模式:

  • 远程代理:可以隐藏一个对象存在于不同控件的事实,也使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求;
  • 虚拟代理:根据需要将资源消耗很大或比较复杂的对象进行延迟,真正需要的时候才进行创建(如:加载图片时显示的图片占位符);
  • 保护代理:为不同用户提供不同级别的目标对象访问权限;
  • 智能引用代理:当一个对象被引用时,提供一些额外的操作;
  • 缓存代理:为开销大的运算结果提供暂时存储,允许多个用户共享结果,以减少计算或网络延迟;
  • 同步代理:在多线程的情况下为主题提供安全的访问;
  • 外观代理:用来隐藏一个类的复杂集合的复杂度,并进行访问控制。

2、案例

  本文中使用上面说的智能引用代理为例简单介绍代理模式。模拟汽车行驶的功能,在汽车行驶前后进行计时,最终得到汽车行驶时间。

2.1、静态代理方式

  下面的示例代码中,CarProxy1类使用了继承方式进行代理,CarProxy2类使用了聚合方式进行代理。

  继承方式和聚合方式的比较:

  在上面的例子中,我们只对时间进行了代理,如果我们在实际开发中不仅要对时间进行代理,还需要对日志、权限等进行代理,那么如果使用继承方式代理,则我们可能会创建很多类,有日志à时间à权限顺序的,有权限à时间à日志顺序的,等等;而如果我们使用聚合方式进行代理,则我们只需要创建时间代理类、日志代理类和权限代理类这三个代理类,然后根据需求调整其调用顺序即可。由此可见,聚合方式比继承方式要好用。

  静态代理方式的代码如下:

  交通工具的(行驶)接口代码:

  1. public interface Movable {
  2. // 汽车行驶
  3. void move();
  4. }

  汽车类代码:

  1. public class Car implements Movable {
  2.  
  3. @Override
  4. public void move() {
  5. try {
  6. System.out.println("汽车正在行驶......");
  7. Thread.sleep((long) (Math.random() * 1000 + 1));
  8. } catch (InterruptedException e) {
  9. e.printStackTrace();
  10. }
  11. }
  12. }

  继承方式的静态代理类CarProxy1中的代码:

  1. public class CarProxy1 extends Car {
  2. @Override
  3. public void move() {
  4. long startTime = System.currentTimeMillis();
  5. System.out.println("汽车开始行驶......");
  6. super.move();
  7. long endTime = System.currentTimeMillis();
  8. System.out.println("汽车停止行驶,共行驶了" + (endTime - startTime) + "毫秒");
  9. }
  10. }

  聚合方式的静态代理类CarProxy2中的代码:

  1. public class CarProxy2 implements Movable {
  2. private Car car;
  3.  
  4. public CarProxy2(Car car) {
  5. this.car = car;
  6. }
  7.  
  8. @Override
  9. public void move() {
  10. long startTime = System.currentTimeMillis();
  11. System.out.println("汽车开始行驶......");
  12. car.move();
  13. long endTime = System.currentTimeMillis();
  14. System.out.println("汽车停止行驶,共行驶了" + (endTime - startTime) + "毫秒");
  15. }
  16. }

  测试类Test中的代码:

  1. public class Test {
  2. public static void main(String[] args) {
  3. // 使用继承方式的静态代理
  4. // Movable movable = new CarProxy1();
  5. // movable.move();
  6.  
  7. // 使用聚合方式的静态代理(通过分析,这种方法更适合代理模式)
  8. Movable movable = new CarProxy2(new Car());
  9. movable.move();
  10. }
  11. }
  1. 运行结果如下图所示:

2.2、动态代理方式

  这里我们使用JDK提供的动态代理模式编写代码。JDK中的动态代理的原理是利用反射机制在运行的时候动态的产生目标类的.class字节码文件,然后使用JDK提供的InvocationHandler接口中的invoke()方法调用目标类中的方法或在此基础上添加更多的业务逻辑,最后调用Proxy.newProxyInstance()方法创建代理类并调用方法。

  动态代理步骤:

  • 创建一个实现了InvocationHandler接口的类,实现invoke()方法;
  • 创建被代理的类及接口;
  • 调用Proxy的静态方法newProxyInstance()创建一个代理类;
  • 通过代理调用方法。

  JDK自从1.3版本开始就引入了动态代理,JDK的动态代理用起来非常简单,但是它有一个显示,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,可以使用cglib包中提供的API。动态代理方式的代码如下:

  交通工具接口Vehicle的代码如下:

  1. public interface Vehicle {
  2. // 交通工具行驶方法
  3. void move();
  4. }

  汽车类Car的代码如下:

  1. public class Car implements Vehicle {
  2.  
  3. @Override
  4. public void move() {
  5. try {
  6. System.out.println("汽车行驶中......");
  7. Thread.sleep((long) (Math.random() * 1000 + 1));
  8. } catch (InterruptedException e) {
  9. e.printStackTrace();
  10. }
  11. }
  12. }

  时间业务处理类TimeInvocationHandler中的代码如下:

  1. public class TimeInvocationHandler implements InvocationHandler {
  2. private Object target;
  3.  
  4. public TimeInvocationHandler(Object target) {
  5. this.target = target;
  6. }
  7.  
  8. /**
  9. * 参数:<br/>
  10. * proxy:被代理的对象<br/>
  11. * method:被代理对象的方法<br/>
  12. * args:方法中的参数<br/>
  13. * </p>
  14. * 返回值:<br/>
  15. * Object:被代理对象的方法的返回值
  16. */
  17. @Override
  18. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  19. // 业务逻辑
  20. long startTime = System.currentTimeMillis();
  21. System.out.println("汽车开始行驶......");
  22. // 调用被代理对象中的方法
  23. method.invoke(target, args);
  24. // 业务逻辑
  25. long endTime = System.currentTimeMillis();
  26. System.out.println("汽车停止行驶,共行驶了" + (endTime - startTime) + "毫秒");
  27. return null;
  28. }
  29. }

  测试类Test中的代码如下:

  1. public class Test {
  2. public static void main(String[] args) {
  3. Car car = new Car();
  4. Class<?> carClass = car.getClass();
  5. TimeInvocationHandler timeHandler = new TimeInvocationHandler(car);
  6. /**
  7. * loader:被代理类的类加载器<br/>
  8. * interfaces:被代理类实现的接口<br/>
  9. * h:InvocationHandler
  10. */
  11. Vehicle v = (Vehicle) Proxy.newProxyInstance(carClass.getClassLoader(), carClass.getInterfaces(), timeHandler);
  12. v.move();
  13. }
  14. }

  运行结果如下图所示:

  最后贴出代理模式的GitHub代码的地址:【GitHub - Proxy】

【设计模式 - 12】之代理模式(Proxy)的更多相关文章

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

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

  2. 设计模式学习心得<代理模式 Proxy>

    在代理模式(Proxy Pattern)中,一个类代表另一个类的功能.这种类型的设计模式属于结构型模式. 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口. 概述 意图 为其他对象提供 ...

  3. 设计模式入门之代理模式Proxy

    //代理模式定义:为其它对象提供一种代理以控制对这个对象的訪问 //实例:鉴于书中给出的样例不太好.并且有些疑问,所以直接用保护代理作为实例 //要求,一旦订单被创建,仅仅有订单的创建人才干够改动订单 ...

  4. 《JAVA设计模式》之代理模式(Proxy)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述代理(Proxy)模式的: 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 代理模式的结 ...

  5. 【转】设计模式(十一)代理模式Proxy(结构型)

    设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ...

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

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

  7. 第12章 代理模式(Proxy Pattern)

    原文   第12章 代理模式(Proxy Pattern) 代理模式 概述: 在软件系统中,有些对象有时候由于跨越网络或者其他的障碍,而不能够或者不想直接访问另一个对象,如果直接访问会给系统带来不必要 ...

  8. 代理模式 PROXY Surrogate 结构型 设计模式(十四)

    代理模式 PROXY 别名Surrogate 意图 为其他的对象提供一种代理以控制对这个对象的访问. 代理模式含义比较清晰,就是中间人,中介公司,经纪人... 在计算机程序中,代理就表示一个客户端不想 ...

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

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

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

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

随机推荐

  1. html5 拖拽的简要介绍

    1,首先,你要告诉计算机那个元素可以拖动,或者是一张图,或者是一个盒子,在标签里面加上 draggable="true"  2,然后,监听该元素被拖动的函数 ondragstart ...

  2. ios开发中加载的image无法显示

    昨天遇到一个较奇葩的问题,imageName加载的图片显示不出来,网上查了好多资料还是没找到解决的方法: 之前图片是放在项目中SupportingFiles文件下的,怎么加载都能显示图片,于是将图片拿 ...

  3. 无线端web开发学习总结

    无线web开发之前要做一些准备工作:一.必需的reset样式库1.其中的重点是盒模型box-sizing:由原来pc端的content-box改为border-box. *, *:before, *: ...

  4. NLPIR.user Not valid license or your license expired! Please feel free to contact pipy_zhang@msn.com

    NLPIR.user Not valid license or your license expired! Please feel free to contact pipy_zhang@msn.com ...

  5. 1、Python django 框架下的word Excel TXT Image 等文件的上传

    1.文件上传(input标签) (1)html代码(form表单用post方法提交) <input class="btn btn-primary col-md-1" styl ...

  6. ecshop标签

    页面标题         {$page_title}页面关键字       {$keywords}     产品分类                 父分类列表 {foreach from=$cate ...

  7. LINUX防火墙firewall、iptables

    (1) 重启后永久性生效: 开启: systemctl enable iptables.service'.ln -s '/usr/lib/systemd/system/iptables.service ...

  8. js对于工厂模式的理解

    有很多人对工厂模式有着这样或者那样不理解的地方,今天我就和大家分享一下我的心得. 其实工厂模式是基于面向对象的一种模式.大家先看这样的一段代码: 其实这个程序很简单,学过js的人都会写,基本没什么问题 ...

  9. js共享onload事件

    问题:通过js进行事件绑定,必须在HTML文档加载完成后再执行js脚本,否则可能因DOM不完整导致无法完成预计的效果,但对于不同的需求如何选用最佳的实现方式呢,这里做了整理,可以做参考. 一.对于小型 ...

  10. nutch-1.7-二次开发-Content中增加编码

    1 识别nutch-1.7的编码,完成 以前1.2是在 org.apache.nutch.parse.html.HtmlParser EncodingDetector detector = new E ...