您的位置:首页 > 编程语言 > Java开发

Java设计模式(05-- 代理模式模式 )

2017-02-23 11:03 507 查看
学习代理模式之前需要了解的内容
1)面向对象的设计思想 2)了解多态概念 3)了解反射原理

本课程包括代理模式的概念及其分类、了解代理模式开发中的应用场景、掌握代理模式的实现方式、
理解JDK动态代理的实现。

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

分类:
1)远程代理:为不同地理的对象提供局域网代表对象,类似客户端和服务器这种模式。
2)虚拟代理:根据需求将资源消耗很大的对象进行延迟处理,真正需要的时候再进行创建。(如一篇文章
的图片很大,我们可以用代替让图片进行延迟加载)
3)保护代理:如论坛的访问权限,我们就可以通过保护代理来实现。
4)智能引用代理:最常用的代理,一般都是需要在代理的服务之前增添某些功能。

以智能引用代理为例其实现方式有静态代理和动态代理两种方式。

静态代理:代理和被代理对象在代理之前都是确定的,他们都是实现了相同的接口或者继承了相同的抽象类。
实现静态方法可以通过继承的方式和聚合的方式来实现
实例:对行驶的汽车进行计时服务。

目标接口(被代理类和代理类都需要实现的接口类):Moveable

1 package com.imooc.pattern.proxy;
2
3 public interface Moveable {
4     void move();
5 }


被代理类(提供汽车行驶功能)Car

1 package com.imooc.pattern.proxy;
2
3 import java.util.Random;
4
5 public class Car implements Moveable {
6
7     public void move() {
8         try {
9             Thread.sleep(new Random().nextInt(1000));
10             System.out.println("汽车行驶中······");
11         } catch (InterruptedException e) {
12             e.printStackTrace();
13         }
14     }
15
16 }


使用继承方式实现静态代理的代理类 CarExtends

1 package com.imooc.pattern.proxy;
2
3 /**
4  * 通过继承的方式实现静态代理
5  * CarExtends通过重写move方法,调用super.move()方法实现了对父类Car的代理,
6  * 同时在super.move()方法前后加入了自己提供的额外服务
7  * @author zplogo
8  *
9  */
10 public class CarExtends extends Car {
11
12     public void move() {
13         long startTime = System.currentTimeMillis();
14         System.out.println("汽车开始行驶······");
15         super.move();
16         long endTime = System.currentTimeMillis();
17         System.out.println("汽车终止行驶····本次行程共花费时间:"+(endTime-startTime)+"毫秒");
18     }
19
20 }


使用聚合方式实现静态代理的代理类 Car3

1 package com.imooc.pattern.proxy;
2
3 /**
4  * 使用聚合的方式实现静态代理
5  * 聚合就是在一个类中需要调用另一个对象,通过构造方法进行注入,然后在实现接口的方法中调用被代理对象的方法
6  * 在该方法前后加入自己的逻辑功能
7  * @author zplogo
8  *
9  */
10 public class Car3 implements Moveable {
11
12     private Car car;
13
14     public Car3(Car car) {
15         super();
16         this.car = car;
17     }
18
19     public void move() {
20         long startTime = System.currentTimeMillis();
21         System.out.println("汽车开始行驶····计时开始··");
22         car.move();
23         long endTime = System.currentTimeMillis();
24         System.out.println("汽车终止行驶····本次行程共花费时间:"+(endTime-startTime)+"毫秒");
25     }
26
27 }


继承方式和聚合方式哪种更好??
现实情况我们需要在代理服务前后做很多功能的叠加,如在move()方法前后不仅需要做计时功能还需要权限功能,日志记录服务。
而Java是单继承的,继承的方式实现静态代理来达到功能的叠加,继承将会无限膨胀下去,因此并不可取。
聚合的方式需要代理类和被代理类都实现相同的接口。

现在我们用聚合的方式完成汽车行驶计时和日志功能的叠加

时间代理类 CarTimeProxy

1 package com.imooc.pattern.jdkproxy;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Proxy;
5
6 import com.imooc.pattern.proxy.Car;
7 import com.imooc.pattern.proxy.Moveable;
8
9 public class JdkProxyTest {
10
11     public static void main(String[] args) {
12         Car car = new Car();
13         InvocationHandler h = new TimeHandler(car);
14         Class<?> cls=car.getClass();
15         /*
16          * loader 被代理类的类加载器
17          * interfaces 实现接口
18          * h  InvocationHandler
19          */
20         Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces() , h);
21         m.move();
22     }
23
24 }


View Code

思考作业:
我们用JDK完成了对Car运行时间的记录,另外我们需要在进行叠加记录日志的功能。

CgLib实现动态代理



首先需要引入Cglib的jar包 cglib-nodep-2.2.jar

实例代码:

被代理类 Train

1 package com.imooc.pattern.cglibproxy;
2
3 public class Train {
4     public void move(){
5         System.out.println("火车行驶中········");
6     }
7 }


Cglib代理类 CglibProxy

1 package com.imooc.pattern.cglibproxy;
2
3 import java.lang.reflect.Method;
4
5 import net.sf.cglib.proxy.Enhancer;
6 import net.sf.cglib.proxy.MethodInterceptor;
7 import net.sf.cglib.proxy.MethodProxy;
8
9 public class CglibProxy implements MethodInterceptor {
10
11     private Enhancer enhancer = new Enhancer();//创建代理类的属性
12
13     public Object getProxy(Class clazz){
14         enhancer.setSuperclass(clazz);//设置创建子类的类(被代理类)
15         enhancer.setCallback(this);
16         return enhancer.create();
17     }
18
19     /*
20      * 拦截所有目标类的方法的调用
21      * object 目标类的实例
22      * m 目标方法反射的对象
23      * args 方法的参数
24      * proxy 代理类的实例
25      */
26     @Override
27     public Object intercept(Object object, Method m, Object[] args,
28             MethodProxy proxy) throws Throwable {
29         System.out.println("开始记录日志·······");
30         //代理类调用父类的方法
31         proxy.invokeSuper(object, args);
32         System.out.println("结束记录日志·······");
33         return null;
34     }
35
36 }


测试代码见上面的客户端测试类 。

智能引用代理在实际开发中应用最广泛,可以进行日志处理,权限管理,事务管理。





动态代理在面向切面编程(AOP)非常有用。

模拟JDK动态代理实现原理(未完待续················)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: