`

代理模式和动态代理

 
阅读更多

所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。Proxy模式是很常见的模式,在我们生活中处处可见,例如我们买火车票不一定非要到火车站去买,可以到一些火车票的代售点去买。寄信不一定是自己去寄,可以把信委托给邮局,由邮局把信送到目的地。

 

1. 代理:一个角色代表别一个角色来完成某些特定的功能。 
比如:生产商,中间商,客户这三者这间的关系 
客户买产品并不直接与生产商打交道,也不用知道产品是如何产生的,客户只与中间商打交道,而中间商就可以对产品进行一些包装,提供一些售后的服务。 

代理模式有三个角色: 1. 抽象主题角色 2. 代理主题角色 3. 实际被代理角色 
其它类通过访问代理主题角色来访问实际被代理角色。 

2. 下面我们来个一个静态代理的实现。 
我以一个坦克为例。 
抽象主题角色:Moveable 

 

Java代码   收藏代码
  1.   package com.gjy.proxy;  
  2.   
  3. blic interface Moveable {  
  4. void move();  


代理主题角色:TanktimeProxy 

Java代码   收藏代码
  1.     package com.gjy.proxy;  
  2.   
  3. public class TanktimeProxy implements Moveable{  
  4.         private Moveable t;  
  5.       
  6.         public TanktimeProxy(Moveable t) {  
  7.             super();  
  8.             this.t = t;  
  9.         }  
  10.   
  11.   
  12.         @Override  
  13.         public void move() {  
  14.             long time1 = System.currentTimeMillis();  
  15.             System.out.println("time1="+time1);  
  16.             t.move();  
  17.             long time2 = System.currentTimeMillis();  
  18.             System.out.println("time2="+time2);  
  19.             System.out.println("运行时间为:"+(time2-time1));  
  20.         }  
  21. }  


实际被代理对象:Tank 

Java代码   收藏代码
  1. package com.gjy.proxy;  
  2.   
  3. public class Tank implements Moveable{  
  4.   
  5.         @Override  
  6.         public void move() {  
  7.             System.out.println("TanK moving........");  
  8.         }  
  9.       
  10. }  



测试: 

Java代码   收藏代码
  1. package com.gjy.proxy;  
  2.   
  3. public class TestTank {  
  4.         public static void main(String[] args) {  
  5.             Tank t = new Tank();  
  6.             Moveable move = new TanktimeProxy(t);  
  7.             move.move();  
  8.           
  9.         }  
  10. }  


从上例可以看到代理主题角色:TanktimeProxy实现了对Tank的move()方法运行时间的计算,而TanktimeProxy,Tank都实现了Moveable接口,通过调用TanktimeProxy的move()方法我们可以实现对Tank的move()方法的运行时间的计算,而不用在Tank的move()方法中作任何实现,这就是代理的作用。代理实现时TanktimeProxy,Tank必需实现Moveable接口。 

下面我想在TanK的move()方法前后加上日志: 
我必需再写一个类来实现这一功能: 

Java代码   收藏代码
  1. package com.gjy.proxy;  
  2.   
  3. public class TanklogProxy implements Moveable{  
  4.         private Moveable t;  
  5.       
  6.         public TanklogProxy(Moveable t) {  
  7.             super();  
  8.             this.t = t;  
  9.         }  
  10.   
  11.   
  12.         @Override  
  13.         public void move() {  
  14.             System.out.println("start move........");  
  15.             t.move();  
  16.             System.out.println("end move......");  
  17.         }  
  18. }  


测试: 

Java代码   收藏代码
  1. package com.gjy.proxy;  
  2.   
  3. public class TestTank {  
  4.     public static void main(String[] args) {  
  5.             Tank t = new Tank();  
  6.             Moveable move = new TanktimeProxy(t);  
  7.             Moveable movet = new TanklogProxy(move);  
  8.             movet.move();  
  9.           
  10.         }  
  11. }  


这样我通过代理在Tank的move()方法前后加入了日志和时间统计的功能,由于TanktimeProxy,TanklogProxy都实现了Moveable接口,所以TanklogProxy可以代理TanktimeProxy,反过来也可以,它们对Tank的代理顺序是可以交换的。 

 比如在玩“极品飞车”这款游戏,如果游戏者手中的金钱达到了一定的数量就可以到车店买一部性能更高的赛车,那么这个卖车的“车店”就是一个典型的“汽车厂家”的“代理”,他为汽车厂家“提供卖车的服务”给有需求的人士。从面向对象的方面考虑,“销售汽车的代理”也是一个对象,那么这个对象也具有一定的状态,在软件项目中这个对象也具有管理财务进销存的基本功能,那么在设计时就要以面向OOP编程的思想来考虑软件的类结构,这个销售汽车的代理也是一个类了。

    【代理模式解释】

    类型:结构模式

    对一些对象提供代理,以限制那些对象去访问其它对象。

    【代理模式UML图

    【代理模式-JAVA代码实现

    新建一个买车的接口:

 

package buy_car_package;
public interface buy_car_package {
    
public void buy_car();
}

 

    新建一个people人类,具有买车的行为,所以实现接口buy_car_package:

 

package buy_car_imple;

import buy_car_package.buy_car_package;
public class people implements buy_car_package {

    
private int cash;
    
private String username;

    
public int getCash() {
        
return cash;
    }

    
public void setCash(int cash) {
        
this.cash = cash;
    }

    
public String getUsername() {
        
return username;
    }

    
public void setUsername(String username) {
        
this.username = username;
    }
    
public void buy_car() {
        System.out.println(username 
+ "买了一台新车");
    }
}

  people类不能拥有车,必须经过proxy代理类的认证,符合条件之后才可以拥有车辆,新建一个代理,这个代理类来考察当前的people是否有资格进行买车:

 

package buy_car_imple;

import buy_car_package.buy_car_package;

public class proxy_buy_car_imple implements buy_car_package {

    
private people people;

    
public people getPeople() {
        
return people;
    }

    
public void setPeople(people people) {
        
this.people = people;
    }

    
public void buy_car() {
        
if (people.getCash() > 3000) {
            System.out.println(people.getUsername() 
+ "" + people.getCash()
                    
+ "块 买了新车 交易结束");
        } 
else {
            System.out.println(people.getUsername() 
+ "金钱不够,请继续比赛!");
        }
    }

}

 

    最后创建一个客户端,用来模拟买车的行为:

 

package run_main;

import buy_car_imple.people;
import buy_car_imple.proxy_buy_car_imple;

public class run_main {
    
public static void main(String[] args) {
        people people_ref1 
= new people();
        people_ref1.setCash(
4000);
        people_ref1.setUsername(
"高洪岩");

        people people_ref2 
= new people();
        people_ref2.setCash(
2000);
        people_ref2.setUsername(
"岩洪高");

        proxy_buy_car_imple proxy_buy_car_imple 
= new proxy_buy_car_imple();
        proxy_buy_car_imple.setPeople(people_ref1);
        proxy_buy_car_imple.buy_car();

        proxy_buy_car_imple.setPeople(people_ref2);
        proxy_buy_car_imple.buy_car();

    }
}

 

    程序运行结果如下:

 

高洪岩花4000块 买了新车 交易结束
岩洪高金钱不够,请继续比赛
!

 

    这样people就不可能自由的拥有车辆,必须经过proxy的认证之后才可以。

    而代理模式在GOF四人帮的介绍中大体有4种使用情景:

    (1)远程代理。典型的就是客户端与webservice使用的情况,客户端由于是针对OOP编程,而不是针对webservice中的方法进行编程,所以得在客户端模拟一下webservice的环境,用proxy来对webservice进行包装,这样就可以使用proxy代理类来远程操作webservice了。

    (2)虚拟代理。比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有100MB,在打开文件时不可能将所有的图片都显示出来,这样就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开。

    (3)安全代理。其实也就是本例中所举的买车的例子,金钱不够不可以买车!

    (4)智能指引。比如在访问一个对象时检测其是否被锁定等情况。

 

 

将你要完成的一些事情交给代理去完成,在此·使用魔乐课堂李兴华老师讲课时用到的一个例子:如果你是图书馆管理员,你主要的工作是管理书籍,但现在上头需要让你也能担当保安的责任,那么,我们可以给图书管理员设置一个代理对象--代理1,保安的责任就让这个代理去做,如果上头又需要你也担当清扫的工作,那么,我们可以再设置一个代理对象:代理2,清扫的工作就交给代理2去做。我想,说这里,该明白的人也都名白了,代理模式就是将你要做的一些事分给一个你的代理去完成。

动态代理模式所必须的3个条件:

1、被代理对象——图书馆管理员

2、可执行者(代理的工作类/接口)——保安/清扫的工作

3、代理类——图书管理员的代理

接下来,我们以上述例子为例,讲解代理模式

首先,我们需要声明一个接口,即被代理对象需要去实现的接口,该接口的直接作用提供在获取动态代理对象的时候需要传入代理对象的类实现的接口对象。

 

[java] view plaincopy
  1. public interface Manager {  
  2.     void manage();  
  3. }  

然后写被代理对象,要求被代理对象实现上面的接口

 

[java] view plaincopy
  1. import com.cen.dao_interface.Manager;;  
  2.   
  3. public class LibraryManager implements Manager {  
  4.   
  5.     @Override  
  6.     public void manage() {  
  7.         System.out.println("在管理图书!");  
  8.     }  
  9. }  

再写好要添加的工作类

 

[java] view plaincopy
  1. import java.lang.reflect.InvocationHandler;  
  2. import java.lang.reflect.Method;  
  3.   
  4. public class BaoAnHandler implements InvocationHandler {  
  5.   
  6.     Object object;  
  7.   
  8.     /** 
  9.      * 构造方法,用于接收传递过来的被代理对象 
  10.      * @param o 
  11.      */  
  12.     public BaoAnHandler(Object o) {  
  13.         this.object = o;  
  14.     }  
  15.   
  16.     @Override  
  17.     public Object invoke(Object proxy, Method method, Object[] args)  
  18.             throws Throwable {  
  19.         Object resultObject;  
  20.         resultObject=method.invoke(object, args);  
  21.         baoAn();//调用新增加的方法  
  22.         return resultObject;  
  23.     }  
  24.     public void baoAn() {  
  25.         System.out.println("在做安保!");  
  26.     }  
  27. }  



 

 

注意,该类必须要实现InvocationHandler接口,并且在invoke方法内将要添加的工作逻辑调用。

 

最后写获取代理类对象的方法实现:

[java] view plaincopy
  1. @Test  
  2.         public void test_HelloWordProxy3() throws Exception {  
  3.             //一个被代理对象  
  4.             Manager manager = new LibraryManager();  
  5.             //一个可执行者,即添加的逻辑  
  6.             InvocationHandler invocationHandler = new BaoAnHandler(manager);  
  7.             //一个代理  
  8.             Manager proxy = (Manager) Proxy.newProxyInstance(manager.getClass()  
  9.                     .getClassLoader(), manager.getClass().getInterfaces(),  
  10.                     invocationHandler);  
  11.             //调用代理的方法  
  12.             proxy.manage();  
  13.         }  

所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。Proxy模式是很常见的模式,在我们生活中处处可见,例如我们买火车票不一定非要到火车站去买,可以到一些火车票的代售点去买。寄信不一定是自己去寄,可以把信委托给邮局,由邮局把信送到目的地。

代理结构如下图所示

Java 代理/动态代理模式(Proxy) - stevinzhu - stevinzhu的博客

以通过代售点买火车票为例,代码实现如下:

//提供买票的公共接口
interface Passenger {
public void buyTicket();
}

//乘客实体
public class RealPassenger implements Passenger {
@Override
public void buyTicket() {
   // TODO Auto-generated method stub
   System.out.print("购买了火车票");
}
}

//代售点
public class Proxy implements Passenger {
Passenger passenger;

public Proxy(Passenger p) {
   this.passenger = p;
}

@Override
public void buyTicket() {
   // TODO Auto-generated method stub
   System.out.println("通过代售点");
   passenger.buyTicket();
}
}

//测试类
public class Client {
public static void main(String[] args) {
   Passenger passenger = new RealPassenger();
   Passenger proxy = new Proxy(passenger);
   proxy.buyTicket();
}
}

输出结果:
通过代售点
购买了火车票

以上的也可叫做静态代理,是为了区别代理模式在Java中的另一种实现——动态代理。动态代理的应用十分广泛,在struts2的拦截器中就用到了动态代理机制。还是以买车票为例子,现在用动态代理来实现,其中不懂的接口方法查查Java api就会明白了,在此不多做解释,代码如下(注意PassengerProxy类):

import java.lang.reflect.*;

public interface Passenger {
public void buyTicket();
}

public class RealPassenger implements Passenger {

@Override
public void buyTicket() {
   // TODO Auto-generated method stub
   System.out.println("购买了车票");
}
}

// 用动态代理实现
public class PassengerProxy implements InvocationHandler {
public Object obj;

// 把obj交给代理类
public Object obj(Object obj) {
   this.obj = obj;
   return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
     .getClass().getInterfaces(), this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
   // TODO Auto-generated method stub
   System.out.println("通过代理");
   method.invoke(obj, args);
   return null;
}
}

public class Client {
public static void main(String[] args) {
   PassengerProxy proxy = new PassengerProxy();
   Passenger passenger = (Passenger) proxy.obj(new RealPassenger());
   passenger.buyTicket();
}
}

分享到:
评论

相关推荐

    java代理模式和动态代理

    ### Java代理模式和动态代理详解 #### 一、概述 在软件工程中,代理模式是一种常用的软件设计模式,主要用于在不直接暴露目标对象的情况下提供一个替代接口。这种模式可以简化客户端与目标对象之间的交互,同时还...

    动态代理设计模式 日志和源码

    动态代理设计模式是一种在运行时创建代理对象的技术,它允许我们为现有的对象提供额外的功能,如日志记录、性能监控、事务管理等,而无需修改原对象的代码。这种模式在Java和许多其他编程语言中都有应用,尤其在...

    代理模式之动态代理

    在Java编程中,代理模式有静态代理和动态代理两种实现方式。本文将主要探讨动态代理,这是一种更灵活且适用于多种场景的技术。 动态代理通常在需要在调用目标方法前后执行额外操作时使用,例如日志记录、性能监控、...

    Java设计模式——代理设计模式(静态代理和动态代理)

    在Java编程中,设计模式是一种解决常见问题的模板或最佳实践,它可以帮助开发者编写更加灵活、可维护和可扩展的代码。代理设计模式是其中的一种,它的主要作用是在...在实际开发中,应根据项目需求选择合适的代理模式。

    Java代理模式Java动态代理

    ### Java代理模式与Java动态代理详解 #### 一、代理模式概述 代理模式是一种软件设计模式,它在客户端和目标对象之间提供了一种间接层。这种模式的主要目的是控制客户端对目标对象的访问,并且可以在不修改原有...

    用Java实现的代理模式之动态代理

    在Java中,代理模式有静态代理和动态代理两种实现方式。本篇将重点讨论"动态代理",这是一种在运行时创建代理对象的技术,使得我们可以在程序运行过程中,根据需要动态地生成具有额外功能的代理类。 动态代理主要由...

    java装饰模式及动态代理模式示例源码

    装饰模式和动态代理模式是Java编程中两种非常重要的设计模式,它们都在代码的扩展性和灵活性方面发挥着关键作用。下面将分别对这两种模式进行详细解释,并结合手写的数据库连接池和动态代理模式的使用进行深入探讨。...

    662.660.JAVA基础教程_动态代理与Java8新特性-代理模式与动态代理(662).rar

    在这个教程中,我们将深入探讨代理模式和动态代理技术,以及Java 8引入的一些重要改进。以下是关于这些主题的详细解释: 首先,代理模式是一种设计模式,它允许在不修改原有对象的情况下,为对象提供额外的功能或...

    代理模式及动态代理资料和源代码

    了解和熟练运用代理模式及其动态代理,能够帮助我们更好地设计和实现具有扩展性和灵活性的系统,特别是在需要进行额外控制或增加非核心业务功能的场景下。通过阅读提供的文档和源代码,你可以更深入地理解这些概念,...

    Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理)

    Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理) Java 动态代理是 Java 编程语言中的一种强大工具,广泛应用于 Spring AOP、Hibernate 数据查询、测试框架的后端 mock、RPC 远程调用、Java 注解...

    java模式设计-代理模式之动态代理.ppt

    在Java中,动态代理是代理模式的一种实现方式,它允许我们在运行时创建代理对象,这种方式比静态代理更加灵活。动态代理在JDK 1.3及以后的版本中得到了支持,主要涉及到三个核心类:`Proxy`、`InvocationHandler`和`...

    代理模式(Proxy Pattern) 1. 概述 1.1 基本概念 1.2 为什么需要代理模式 1.3 代理模式的四个角色 2. 代理模式的类型 2.1 静态代理 2.2 JDK动态代理

    3. 代理模式的UML类图和基本实现 3.1 UML类图 3.2 基本实现 3.2.1 静态代理基本实现 3.2.2 JDK动态代理基本实现 3.2.3 CGLIB动态代理基本实现 3.3 三种代理方式的对比 4. 代理模式的详细示例(Java实现) 4.1 场景...

    java静态代理、动态代理、装饰设计模式

    在Java编程中,代理模式是一种常见的设计模式,它允许我们为一个对象提供一个代理以控制对这个对象的访问。代理模式通常用于增加额外的功能或在访问原对象时进行额外的操作,比如日志记录、安全控制、性能统计等。...

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

    代理模式在Android开发中扮演着重要角色,它提供了扩展功能和控制原对象行为的手段,而无需修改原对象的代码。通过理解并熟练运用代理模式,开发者能够编写出更灵活、可维护的代码,同时提高应用程序的性能和用户...

    代理模式的使用示例程序

    代理模式的实现通常有两种方式:静态代理和动态代理。静态代理是在编译时就确定了代理关系,需要为每个原始对象创建一个对应的代理类。动态代理则是在运行时动态创建代理对象,这通常通过Java的反射API或C#的`System...

    代理模式-静态动态代理-jdk动态代理-cglib动态代理

    在Java中,代理模式有多种实现方式,包括静态代理、JDK动态代理和CGLIB动态代理。 **静态代理** 静态代理是最早也是最基础的代理实现方式。在静态代理中,我们需要创建一个代理类,这个代理类与原始类(被代理类)...

    Java变成模式-代理模式

    Java编程模式-代理模式。介绍了静态代理模式和动态代理模式

    java 动态代理模式 适配器模式

    Java动态代理模式与适配器模式是两种在软件设计中常用的设计模式,它们都有各自的优点和应用场景。在Java中,动态代理模式主要依赖于Java的反射API和InvocationHandler接口,而适配器模式则用于解决不同接口之间的...

    代理模式(含动态代理讲解)【Spring AOP实质】

    在Java中,代理模式主要有两种实现方式:静态代理和动态代理。 1. 静态代理: 在静态代理中,我们需要手动创建一个代理类,这个代理类实现了与目标类相同的接口。代理类中会持有目标对象的引用,并在调用目标对象...

Global site tag (gtag.js) - Google Analytics