java设计模式(10):代理模式(Proxy)

一,定义:  代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。

二,其类图:

三,分类一:静态代理

1,介绍:也就是需要我们为目标对象编写一个代理对象,在编译期就生成了这个代理对象,然后通过访问这个代理,来实现目标对象某些功能。

2,简单应用:在这里我们看一个简单的登录登出的例子:

登录功能的接口:

[java] view
plain
copyprint?

  1. /**
  2. * 公共接口,目标对象和代理都来实现
  3. */
  4. public interface ILogin{
  5. //登录
  6. void login();
  7. //登出
  8. void logout();
  9. }

实现的目标接口:

[java] view
plain
copyprint?

  1. /**
  2. * 目标对象,实现公共接口,达到登录登出的功能
  3. */
  4. public class Reallogin implements ILogin{
  5. public void login(){
  6. try {
  7. Thread.sleep(3200);
  8. } catch (InterruptedException e) {
  9. e.printStackTrace();
  10. }
  11. System.out.println("登录系统.....");
  12. }
  13. public void logout(){
  14. try {
  15. Thread.sleep(2200);
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. }
  19. System.out.println("退出系统....");
  20. }
  21. }

大家看见了,上边的方法中我们加入了线程的睡眠,因为我想通过代理模式来测试登录登出的时间,因为JAVA程序我们遵循OCP(对扩展开放,对修改关闭)原则,所以为了不修改原来代码,我们来采用静态代理模式:

Proxy(代理对象)的代码:

[java] view
plain
copyprint?

  1. /**
  2. * 代理对象,代理目标对象Reallogin
  3. */
  4. public class ProxyLogin implements ILogin{
  5. //此类中包含了目标对象
  6. private Reallogin target;
  7. //构造方法
  8. public ProxyLogin (Reallogin target){
  9. this.target = target;
  10. }
  11. @Override
  12. public void login() {
  13. //开始时间
  14. long begin = System.currentTimeMillis();
  15. target.login();
  16. //结束时间
  17. long end = System.currentTimeMillis();
  18. System.out.println("耗费时长"+(end-begin)+"毫秒");
  19. }
  20. @Override
  21. public void logout() {
  22. long begin = System.currentTimeMillis();
  23. target.logout();
  24. long end = System.currentTimeMillis();
  25. System.out.println("耗费时长"+(end-begin)+"毫秒");
  26. }
  27. }

好,通过代理模式,非常简单的实现了对登录登出时间的捕获,但是,假如客户突然要求我们对所有的类方法的时间进行捕获,那该怎么办呢?总不能每一个类,都写一个代理类,那样太麻烦了吧!怎么呢???

3,分析:通过这里例子以及扩展我们来看一下静态代理模式的缺点吧:

a,如果出现上边的需求,那么势必会出现类爆炸的结果;

b,当然捕捉方法执行时间的代码都一样,我们每个方法都写,每个类都写,这也是代码的重复,没有达到代码复用的效果,这也完全违背了面向对象设计的原则。

4,思考:防止出现类爆炸,使代码能够得到复用。我们能不能用一个代理类,来代理所有需要计算方法运行时间呢??? 看下边的动态代理模式。

四,动态代理

1,介绍:通过反射机制,利用JDK提供的Proxy类,在程序运行的时候在内存中根据目标对象来创建代理对象,避免了类爆炸的出现。代理方法只写一此,使代码得到了复用。

2,解决上边的问题:

a,代理方法的编写:

[java] view
plain
copyprint?

  1. /**
  2. * 此类需要实现InvocationHandler接口
  3. * 调用处理器,当代理对象调用代理方法的时候,注册在调用处理器中的invoke方法会自动调用。
  4. */
  5. public class TimerInvocationHandler implements InvocationHandler {
  6. //目标对象,通过反射机制获得
  7. private Object target;
  8. //构造方法
  9. public TimerInvocationHandler(Object target){
  10. this.target = target;
  11. }
  12. /**
  13. *  参数:
  14. *          Object proxy:代理对象的引用,proxy变量中保存代理对象的内存地址(这个参数很少用)
  15. *          Method method:目标对象的目标方法。
  16. *          Object[] args:目标对象的目标方法执行的时候所需要实参。
  17. */
  18. @Override
  19. public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
  20. //开始时间
  21. long begin = System.currentTimeMillis();
  22. //执行目标对象中的方法
  23. Object retValue = method.invoke(target, args);
  24. //结束时间
  25. long end = System.currentTimeMillis();
  26. //计算时间
  27. System.out.println("耗费时长"+(end-begin)+"毫秒");
  28. return retValue;
  29. }
  30. }

b,注意这里的测试程序的编写:

[java] view
plain
copyprint?

  1. /**
  2. * 注意:JDK内置的动态代理Proxy只能代理接口
  3. *(如果既想代理接口又想代理抽象类需要使用第三方组件:例如cglib)
  4. */
  5. public class Test {
  6. public static void main(String[] args) {
  7. //创建目标对象
  8. ILogin target = new ProxyLogin();
  9. //创建代理对象:通过JDK内置的动态代理类java.lang.reflect.Proxy完成代理对象的动态创建
  10. //参数:
  11. ClassLoader loader;
  12. 这里的类装载器主要是用来装载在内存中生成的那个临时的字节码,
  13. 代理类的类装载器需要和目标类的类装载器一致。
  14. Class[] interfaces;
  15. 代理类和目标类必须实现“同一些”接口。(一个类可以同时实现多个接口)
  16. InvocationHandler handler;
  17. 当代理对象调用代理方法的时候,“注册”在调用处理器中的invoke方法会自动调用。
  18. ILogin proxy = (IUserService)Proxy.newProxyInstance(target.getClass().getClassLoader(),new Class[]{IUserService.class},new TimerInvocationHandler(target));
  19. //通过执行代理对象的代理方法去执行目标对象的目标方法
  20. proxy.login();
  21. proxy.logout();
  22. }
  23. }

3,动态代理模式相对来说比较难了解,因为它运用了反射机制。但是想象现实生活中,还是挺容易理解的,例如,工作中介,相当于代理模式中的代理对象,它可以为不同人找不同的工作,我们可以没有见过咱们生活中每个人都有一个工作中介代理对象吧。所以这里可以理解为功能代理对象,即为所有类代理可以实现同一种功能,例如上边的捕捉时间。

五,动态模式解决Service层的JDBC代码,以及一些重复的代码:

大家都直到Service层是用来写业务代码的,但是当出现事物时,我们需要在业务层进行事物的开启,提交,回滚,结束,这样就有了JDBC代码了,而且都是重复的,怎么办呢,我们可以为这些利用事物的业务层利用代理模式来解决这个问题。

看一下这个service层中的方法,里边有JDBC代码,而且每个Servlet都需要写,非常不满足规范:

[java] view
plain
copyprint?

  1. public boolean saveEnterprise(Enterprise en, List<EnInv> eninvs) throws Exception {
  2. Connection conn =null;
  3. int count=0 ;
  4. try {
  5. //获取数据连接对象
  6. conn=DBUtil.getConnection();
  7. //事物的开始
  8. DBUtil.beginTransaction(conn);
  9. count=ienterpriserDao.InsertEnterpriseDao(en, eninvs);
  10. //事物的提交
  11. DBUtil.commitTransaction(conn);
  12. } catch (Exception e) {
  13. try {
  14. //事物的回滚
  15. DBUtil.rollbackTransaction(conn);
  16. } catch (SQLException e1) {
  17. e1.printStackTrace();
  18. }
  19. e.printStackTrace();
  20. }finally{
  21. try {
  22. //事物的结束
  23. DBUtil.endTransaction(conn);
  24. } catch (SQLException e) {
  25. e.printStackTrace();
  26. }
  27. DBUtil.close(conn, null, null);
  28. }
  29. return count==(1+eninvs.size());

通过Prox动态代理:

代理方法的编写:

[java] view
plain
copyprint?

  1. public class TransactionInvcationHandler implements InvocationHandler {
  2. //目标对象的创建
  3. private Object target;
  4. //编写构造方法,
  5. public TransactionInvcationHandler(Object target){
  6. this.target=target;
  7. }
  8. @Override
  9. /**
  10. * 利用事物的操作的调用事物处理
  11. */
  12. public Object invoke(Object proxy, Method method, Object[] args)
  13. throws Throwable {
  14. Object retValue=null;
  15. Connection conn=null;
  16. try{
  17. conn=DBUtil.getConnection();
  18. //开启事物
  19. DBUtil.beginTransaction(conn);
  20. //执行目标对象的方法
  21. retValue=method.invoke(target, args);
  22. //提交事物
  23. DBUtil.commitTransaction(conn);
  24. }catch(Exception e ){
  25. //回滚事物
  26. DBUtil.rollbackTransaction(conn);
  27. e.printStackTrace();
  28. }finally{
  29. //关闭事物
  30. DBUtil.endTransaction(conn);
  31. DBUtil.close(conn, null, null);
  32. }
  33. return retValue;
  34. }
  35. }

这样这个Service就只需要写这两句话了:

[java] view
plain
copyprint?

  1. public boolean saveEnterprise(Enterprise en, List<EnInv> eninvs) throws Exception {
  2. int count=0 ;
  3. count=ienterpriserDao.InsertEnterpriseDao(en, eninvs);
  4. return count==(1+eninvs.size());
  5. }

当然Servlet的调用和上边的那个测试程序一样,我就不再写了。总而言之,动态代理模式模仿我们生活中的中介代理,使我们的程序代码达到了非常好的复用和分类清楚,非常实用。

代理模式的其他应用:

1,远程代理,为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。

2,虚拟代理,根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。例如,网页中在图片出来以前现出来文字。

3,安全代理,用来控制真实对象访问时的权限。

4,智能代理,是指当调用真实的对象时,代理处理另外一些事。

总而言之,这次的学习,有感觉软件和我们生活是息息相关的,善于发现生活的点点滴滴,从软件中联想生活会理解的更深,学习的更好!!!!

时间: 2024-10-10 14:53:49

java设计模式(10):代理模式(Proxy)的相关文章

浅谈JAVA设计模式之——代理模式(proxy)

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/45568963 一.概述 为其他对象提供一种代理以控制对这个对象的访问. 二.适用性 1.远程代理(RemoteProxy)为一个对象在不同的地址空间提供局部代表. 2.虚代理(VirtualProxy)根据需要创建开销很大的对象. 3.保护代理(ProtectionProxy)控制对原始对象的访问. 4.智能指引(SmartReference)取代了简单的指针,它在访问对象时执行

设计模式之代理模式(Proxy)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

JAVA设计模式(3)----代理模式

1.  什么是代理模式?Proxy Pattern 代理模式定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 通俗的讲,代理模式就是我很忙没空理你,你要想找我可以先找我的代理人,代理人和被代理人继承同一个接口.代理人虽然不能干活,但是被代理的人可以干活. 这个例子中有水浒传中的这么几个人:名垂青史的潘金莲,王婆,西门大官人.西门庆想要找潘金莲,需要找王婆做代理.首先定义一个接口:Kin

设计模式三: 代理模式(Proxy) -- JDK的实现方式

设计模式三: 代理模式(Proxy) -- JDK的实现方式 简介 代理模式属于行为型模式的一种, 控制对其他对象的访问, 起到中介作用. 代理模式核心角色: 真实角色,代理角色; 按实现方式不同分为静态代理和动态代理两种; 意图 控制对其它对象的访问. 类图 实现 JDK自带了Proxy的实现, 下面我们先使用JDK的API来演示代理如何使用, 随后再探究Proxy的实现原理,并自己来实现Proxy. JDK代理类的使用: (InvocationHandler,Proxy) 使用JDK实现的代

java设计模式6——代理模式

java设计模式6--代理模式 1.代理模式介绍: 1.1.为什么要学习代理模式?因为这就是Spring Aop的底层!(SpringAop 和 SpringMvc) 1.2.代理模式的分类: 静态代理 动态代理 1.3.代理模式关系图(以租房子为例) 2.静态代理 2.1.角色分析: 抽象角色:一般会使用接口或者抽象类来解决 真实角色:被代理的角色 代理客户:代理真实角色.代理真实角色后,我们一般会做一些附属的操作 客户:访问代理对象的人 2.2.例1(租房子演示) 2.2.1.抽象角色实现(

JAVA设计模式之代理模式

学编程吧JAVA设计模式之代理模式发布了,欢迎通过xuebiancheng8.com来访问 一.概述 给某一个对象提供一个代理,并由代理对象来完成对原对象的访问.代理模式是一种对象结构型模式. 二.适用场景 当无法直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口. 三.UML类图 四.参与者 1.接口类:Subject 它声明了真实访问者和代理访问者的共同接口,客户端通常需要针对接口角色进行编程. 2.代理类

Android设计模式之代理模式 Proxy

一.概述 代理模式也是平时比较常用的设计模式之一,代理模式其实就是提供了一个新的对象,实现了对真实对象的操作,或成为真实对象的替身.在日常生活中也是很常见的.例如A要租房,为了省麻烦A会去找中介,中介会替代A去筛选房子,A坐享中介筛选的结果,并且交房租也是交给中介,这就是一个典型的日常生活中代理模式的应用.平时打开网页,最先开到的一般都是文字,而图片等一些大的资源都会延迟加载,这里也是使用了代理模式. 代理模式的组成: Abstract Subject:抽象主题-声明真实主题和代理主题共同的接口

设计模式之代理模式---Proxy Pattern

模式的定义 代理模式(Proxy Pattern)也叫做委托模式,定义如下: Provide a surrogate or placeholder for another object to control access to is. 为其他对象提供一种代理以控制对这个对象的访问. 类型 结构类 模式的使用场景 想想现实世界中,打官司为什么要找个律师?因为你不想参与中间过程的是是非非,只要完成自己的工作就可以,其它的事情比如事前调查,事后追查都可以由律师来负责,这就可以减少你的负担.代理模式使用

设计模式——10.代理模式

1. 模式动机 在某些情况下,一个客户不想或者不能直接引用一个对 象,此时可以通过一个称之为“代理”的第三者来实现 间接引用.代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务. 通过引入一个新的对象(如小图片和远程代理 对象)来实现对真实对象的操作或者将新的对 象作为真实对象的一个替身,这种实现机制即 为代理模式,通过引入代理对象来间接访问一 个对象,这就是代理模式的模式动机. 2. 模式定义 代理模式(Proxy

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

一,总体概要 1,笔者浅谈 当我们浏览网页时,网页中的图片有时不会立即展示出来,这就是通过虚拟代理来替代了真实的图片,而代理存储了真实图片的路径和尺寸,这就是代理方式的一种. 代理模式是比较有用途的一种模式,而且变种较多(虚代理.远程代理.copy-on-write代理.保护代理.Cache代理.防火墙代理.同步代理.智能指引),应用场合覆盖从小结构到整个系统的大结构, 我们也许有代理服务器等概念,代理概念可以解释为:在出发点到目的地之间有一道中间层,意为代理. 代理对象角色内部含有对真实对象的