浅析代理模式(转)

前言:

  代理模式作为常见的设计模式之一,在项目开发中不可或缺。本文就尝试着揭开代理的神秘面纱,也欢迎各路人批评指正!

1.如何实现代理:

【假设有个关于汽车移动(move)的计时需求】 设计:Moveable接口,一个Car的实现类;两个代理CarTimer,TimeHandler.UML图如下:

1)继承

 1 package com.gdufe.proxy;
 2
 3 import java.util.Random;
 4
 5 public class CarTimer extends Car {
 6
 7     @Override
 8     public void move() {
 9         long start=System.currentTimeMillis();
10         super.move();        //调用父类的move()方法
11         try{
12             Thread.sleep(new Random().nextInt(10000));
13         }catch(Exception e){
14             e.printStackTrace();
15         }
16         long end=System.currentTimeMillis();
17         System.out.println("I'm time machine.Time for moving:"+(end-start));
18     }
19 }

View Code

2)组合

 1 package com.gdufe.proxy;
 2
 3 import java.util.Random;
 4
 5 public class TimeHandler implements Moveable {
 6     private Moveable m;
 7     public TimeHandler(Moveable m) {
 8         this.m = m;
 9     }
10     @Override
11     public void move() {
12         long start=System.currentTimeMillis();
13         m.move();
14         try{
15             Thread.sleep(new Random().nextInt(10000));
16         }catch(Exception e){
17             e.printStackTrace();
18         }
19         long end=System.currentTimeMillis();
20         System.out.println("I'm time machine.Time for moving:"+(end-start));
21     }
22
23 }

View Code

 

客户端代码:

 1 package com.gdufe.proxy;
 2
 3 public class Client {
 4     public static void main(String[] args) {
 5         System.out.println("继承实现代理:");
 6         new CarTimer().move();
 7         System.out.println("组合实现代理:");
 8         new TimeHandler(new Car()).move();
 9     }
10 }

 

输出结果:

继承实现代理:
Car moving...
I'm time machine.Time for moving:7080
组合实现代理:
Car moving...
I'm time machine.Time for moving:5169

 

分析:从上述例子实现当中,我们第一感觉自然是分不出两种代理的实现方式孰优孰劣。且继续往下面看。

2.灵活代理-接口切换

【假设现在特殊需求不确定:“汽车移动之前先往左还是先往右”】 很明显,我们此时若使用继承的方式实现代理,则后续很不容易维护,而且会形成臃肿的继承链;但使用接口的方式我们发现仅需要两个代理类:TurnLeft,TurnRight。而且,不管后续需求如何都只需要做简单的调整。UML图如下:

----------

TurnLeft.java

 1 package com.gdufe.proxy;
 2
 3 public class TurnLeft implements Moveable {
 4     private Moveable m;
 5     public TurnLeft(Moveable m) {
 6         this.m = m;
 7     }
 8     @Override
 9     public void move() {
10         System.out.println("turn left...");
11         m.move();
12     }
13
14 }

View Code

TurnRight.java

 1 package com.gdufe.proxy;
 2
 3 public class TurnRight implements Moveable {
 4
 5     private Moveable m;
 6     public TurnRight(Moveable m) {
 7         this.m = m;
 8     }
 9     @Override
10     public void move() {
11         System.out.println("turn right");
12         m.move();
13     }
14
15 }

View Code

客户端代码:

 1 package com.gdufe.proxy;
 2
 3 public class Client0 {
 4
 5     /**
 6      * @param args
 7      */
 8     public static void main(String[] args) {
 9         System.out.println("Turn right,then left before moving:");
10         test1();
11
12         System.out.println("Turn left,then right before moving:");
13         test2();
14     }
15     //对接口的实现内外包装
16     private static void test1() {
17         Car car  = new Car();
18         Moveable m1 = new TurnLeft(car);
19         Moveable m2 = new TurnRight(m1);
20         m2.move();
21     }
22     public static void test2(){
23         Car car = new Car();
24         Moveable m1 = new TurnRight(car);
25         Moveable m2 = new TurnLeft(m1);
26         m2.move();
27     }
28
29 }

 

输出结果:

Turn right,then left before moving:
turn right
turn left...
Car moving...
Turn left,then right before moving:
turn left...
turn right
Car moving...

 

========================

3.动态代理:

其实,不管是继承还是组合的方式,我们上面实现的都仅仅是“静态代理”,也是我们平时用的比较多的。现在,我们开始聊聊Java的神器---“动态代理”。 【假设现在需要实现一个“万能”的日志工具,即不管对任何类的任何方法都可以动态对其进行日志操作】 例如:上面的例子中,请思考如何实现在汽车移动之前进行日志操作? 常规的静态代理方式当然可以实现,下面我们就利用Java中的Proxy类进行实现。UML图如下:

 

添加关键类:LogHandler.java

 1 package com.gdufe.proxy;
 2
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5
 6 public class LogHandler implements InvocationHandler {
 7
 8     //被代理对象
 9     private Object proxied;
10
11     public LogHandler(Object proxied) {
12         this.proxied = proxied;
13     }
14     @Override
15     public Object invoke(Object proxy, Method method, Object[] args)
16             throws Throwable {
17         System.out.println("I'm log machine.");
18         return method.invoke(proxied);
19     }
20
21 }

 

客户端代码:

 1 package com.gdufe.proxy;
 2
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Proxy;
 5
 6 public class Client1 {
 7
 8     /**
 9      * @param args
10      */
11     public static void main(String[] args) {
12
13         //单独创建Moveable接口对象
14         Moveable m=null;
15         m = new Car();
16         m = new TimeHandler(m);
17
18         //初始化LogHandler实现的InvacationHandler接口
19         InvocationHandler h =  new LogHandler(m);
20         m = (Moveable) Proxy.newProxyInstance(
21                 Moveable.class.getClassLoader(),
22                 new Class[] {Moveable.class},h);
23
24         //m在动态代理处理完后,move()方法已被修改
25         m.move();
26     }
27
28 }

 

输出结果:

I'm log machine.
Car moving...
I'm time machine.Time for moving:110

 

分析:

  上述的实现代码对于刚接触Java的朋友来说估计比较费解。要理解其过程,至少对java的反射机制有一定的理解。看穿了的话,其实动态代理的关键环节,就在newProxyInstance()操作上。代码实现的关键步骤:

Step1:初始化被代理的对象(如上图中的TimeHandler);

Step2:创建一个实现了InvocationHandler接口的类,在invoke()方法进行你希望执行的代理操作(如上图的LogHandler);

Step3:将通过Proxy拿到的新对象赋给最终要实现的接口,最后调用该接口方法(如代码中的“m.move()”)。

---------------------------------------------------------------------

有朋友可能犯迷糊了,动态代理的内部实现过程呢?Proxy是怎样一步一步识别到Car的呢?

请看图:

 

注意:$Proxy类是虚拟存在的,在Java API中是找不到的。也就是说,它只存在于中间过程。所以,为方便大家理解就加上了。)

     那么,到底动态代理适用于什么情形呢?从上面汽车的简单日志实例也许还难以看出。下面我们再引入一个测试。 【假设现在增加一个司机(Driver)类,其实现了Speakable接口;很明显他跟汽车没有很直接的关联,那么现在我们利用动态代理的方式将上面的LogHandler加到司机的speak()方法上】 ---------- 客户端代码:

 1 package com.gdufe.proxy;
 2
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Proxy;
 5
 6 public class Client2 {
 7
 8     /**
 9      * @param args
10      */
11     public static void main(String[] args) {
12         Moveable m=null;
13         m = new Car();
14
15         Speakable s =null;
16         s = new Driver();
17
18         InvocationHandler h = null;
19         h=new LogHandler(m);
20         m = (Moveable) Proxy.newProxyInstance(Moveable.class.getClassLoader(),new Class[] {Moveable.class},h);
21         m.move();
22
23         //司机被代理
24         h = new LogHandler(s);
25         s = (Speakable)Proxy.newProxyInstance(Speakable.class.getClassLoader(),new Class[]{Speakable.class}, h);
26         s.speak();
27         }
28
29 }

 

输出结果:

I'm log machine.
Car moving...
I'm log machine.
Driver speak...

  在汽车move()跟司机speak()之前,都自动实现LogHandler操作!

-----------------------------------------------------

后语:

通过上述例子,总结动态代理优点: ·适用任何类的任何方法; ·使用灵活,可随时将代理工具类加入或抽出。

  动态代理是Java语言的精华所在,很多的开发框架都是基于其内部原理。本人目前对动态代理的理解也仅限于此,欢迎对Java有深度学识的朋友拍砖,谢谢~

http://www.cnblogs.com/SeaSky0606/p/4732550.html

 

时间: 2025-01-31 07:23:25

浅析代理模式(转)的相关文章

浅析设计模式中的代理模式在C++编程中的运用_C 语言

由遇到的问题引出代理模式 至少在以下集中情况下可以用代理模式解决问题: 创建开销大的对象时候,比如显示一幅大的图片,我们将这个创建的过程交给代理去完成,GoF 称之为虚代理(Virtual Proxy): 为网络上的对象创建一个局部的本地代理,比如要操作一个网络上的一个对象(网络性能不好的时候,问题尤其突出),我们将这个操纵的过程交给一个代理去完成,GoF 称之为远程代理(Remote Proxy): 对对象进行控制访问的时候,比如在 Jive 论坛中不同权限的用户(如管理员.普通用户等)将获得

浅析.NET开发中代理模式的使用

当我们需要使用的对象很复杂或者需要很长时间去构造,这时就可以使用代理模式(Proxy).例如:如果构建一个对象很耗费时间和计算机资源,代理模式(Proxy)允许我们控制这种情况,直到我们需要使用实际的对象.一个代理(Proxy)通常包含和将要使用的对象同样的方法,一旦开始使用这个对象,这些方法将通过代理(Proxy)传递给实际的对象. 一些可以使用代理模式(Proxy)的情况: 1.一个对象,比如一幅很大的图像,需要载入的时间很长. 2.一个需要很长时间才可以完成的计算结果,并且需要在它计算过程

大话设计模式之代理模式

代理模式的应用场合: 一,远程代理 二,虚拟代理 三,安全代理 简单来说,就是两个类共同实现接口,一个实现,一个调用这个实现.而调用实现的类,就是代理类. 针对书上的代码,我加了一个NAME变量和一个SHOWNAME方法.更加直观展示代理的细节. 1 /* 2 * Created by SharpDevelop. 3 * User: home 4 * Date: 2013/4/21 5 * Time: 9:33 6 * 7 * To change this template use Tools

设计模式之代理模式(Proxy Pattern)

1 代理模式定义 定义:给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原对象,而是通过代理对象间接地操控原对象. 本篇文章主要介绍的是静态代理,关于动态代理请参考:设计模式之动态代理(dynamic proxy) 2 代理模式的作用 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 通过代理类对原有类进行功能增强,如增加缓存.异常处理.日志处理等,Spring AOP用的就是(动态)代理模式 3 代理模式一

javascript 之 代理模式

代理模式说明 说明:顾名思义就是用一个类来代替另一个类来执行方法功能,这个模式跟装饰模式有点相似,不一样的是,代理模式是代替客户初始化被代理对象类,而装饰模式采用接口或初装饰者参数引用的方式来执行的. 在动态面向对象语言里,代理模式即起到控制修饰被代理类的作用,也对被代理类起到了充分的隐藏保护作用:被代理类只到我们需要时,才被间接初始化调用: 场景描述: 很常见到的就是租房子的例子,房客要租房子,房东要把房子租出去,但是房客跟房东都没怎么有空找房子或在家等着有人看房子,就一同去找房屋中介.房东把

php设计模式 Proxy (代理模式)

复制代码 代码如下: <?php /** * 代理模式 * * 为其他对象提供一个代理以控制这个对象的访问 * */ interface Proxy { public function request(); public function display(); } class RealSubject { public function request() { echo "RealSubject request<br/>"; } public function disp

代理模式(proxy pattern) 未使用代理模式 详解

如果需要监控(monitor)类的某些状态, 则需要编写一个监控类, 并同过监控类进行监控. 但仅仅局限于本地, 如果需要远程监控, 则需要使用代理模式(proxy pattern). 具体方法: 1. 类中需要提供状态信息, 并提供一些get方法, 进行调用. /** * @time 2014年7月11日 */ package proxy; /** * @author C.L.Wang * */ public class GumballMachine { String location; //

传统设计模式(十一)代理模式

所谓的代理,就是代表某个真实的对象.在这个设计模式中,代理可以假装自己是远程对象,但其实只是一个中间角色.客户对象所作的就像是在做远程方法调用,但其实只是调用本地资源中得"代理"对象上得方法,再由代理处理所有网络通信的底层细节. 其实其实项目实例神马的 根本就没必要了 看一下Web Service的调用方式大家也许就明白了,它会在客户端生成一个代理类 - - 已经很完美的诠释了代理模式这个概念 虫子放下水 直接拿以前监控项目中客户端采集的代理方法了 --_____-- 服务器端 [We

Java的代理模式

前几天一个网友指出了我的文章中一些有失偏颇之处,那些文章都是我在阅读Java Core的时候做的总结,顺便加上我个人的一些理解.因为看的e文版,理解上有些地方可能还欠妥.下面谈一下对Java中代理模式(Proxy)的认识. 代理,想必大家都应该知道是什么冬冬了,一般的手机产商都有代理商,歌星们都有自己的经纪人,如此这些都可以看作是一种代理模式.下面我选择如下的一种情景来进行讲述:某董事长出差,但是此时公司有个聚会,董事长买单,但是由他的秘书去结帐.我们就权且把这个看作一个代理行为,^_^. 首先