码迷,mamicode.com
首页 > 其他好文 > 详细

四(2)、复用类补充之关于代理模式的一点理解

时间:2015-07-26 20:35:57      阅读:103      评论:0      收藏:0      [点我收藏+]

标签:

一、关于代理模式的几个概念

1.比如A要去租房,通过中介B,租到C家的房子,这里B就是A的代理。

代理可以认为是之前介绍的组合和继承的折中模式,它有继承的部分也有组合的部分。

2、代理的结构

1)抽象主题角色: 声明了真实主题和代理主题的共同的接口。

2)代理主题角色:内部含有真实主题的引用, 从而可以再任何时候操作真实主体对象;提供了一个与真实主题相同的接口,以便可以替代真实主题。

3)真实主题角色:抽象主题的实现,是具体被代理的对象。

 

二、三种常见的代理模式

1.普通代理模式

 1 package com.test;
 2 
 3 /**
 4  * 抽象主题角色
 5  */
 6 public abstract class Subject {
 7     public abstract void request();
 8 }
 9 
10 //-------------分割线--------------------------
11 package com.test;
12 
13 /**
14  * 真实主题对象
15  */
16 public class RealSubject extends Subject{
17     @Override
18     public void request() {
19         System.out.println("真实主题对象");
20     }
21 }
22 
23 //-------------分割线--------------------------
24 package com.test;
25 
26 /**
27  * 代理对象
28  */
29 public class ProxySubject extends Subject{
30     
31     private RealSubject realSubject;//代理对象里面放真实对象
32     
33     public ProxySubject() {
34         
35     }
36     
37     @Override
38     public void request() {
39         pre();
40         if (null == realSubject) {
41             realSubject = new RealSubject();
42         }
43         realSubject.request();
44         after();
45     }
46     
47     private void pre() {
48         System.out.println("前置");
49     }
50     
51     private void after() {
52         System.out.println("后置");
53     }
54     
55     public static void main(String[] args) {
56         Subject sub = new ProxySubject();//父类声明,指向子类代理对象
57         sub.request();
58     }
59 }

 

结果如下:

技术分享

使用代理模式的优点,是可以在真实请求的前后,加一些控制。使用这种方式,要求知道接口和实现类的信息。

 

2.使用JDK自带的Proxy,InvocationHandler,Mehtod来实现代理模式(这种是动态代理,对比来讲前一种是静态代理)

 1 package com.test;
 2 
 3 /**
 4  * 抽象主题角色
 5  */
 6 public interface Subject { //这里需要是接口,跟上面的例子相比,上面的例子可以写成抽象类,也可以写成接                              //口,但是这个例子里面将只能够写成接口
 7     public abstract void request();
 8 }
 9 
10 //-------------------------------分割线----------------------------
11 package com.test;
12 
13 /**
14  * 真实主题对象
15  */
16 public class RealSubject implements Subject{
17     @Override
18     public void request() {
19         System.out.println("真实主题对象");
20     }
21 }
22 
23 //-------------------------------分割线----------------------------
24 package com.test;
25 
26 import java.lang.reflect.InvocationHandler;
27 import java.lang.reflect.Method;
28 import java.lang.reflect.Proxy;
29 
30 /**
31  * 创建代理类
32  */
33 public class JDKProxySubject implements InvocationHandler{
34     private Object targetObject;//目标对象, 我们这个工厂就是生产出这个对象的代理对象
35     
36     //创建代理对象的具体方法实现
37     public Object createProxyInstance(Object targetObject) {
38 
39         this.targetObject = targetObject;
40         /*这个Proxy对象就是jdk自带的一个类,用其newProxyInstance方法
41         来进行创建代理对象, 第一个参数是类加载器, 第二个参数是实现的接口数组
42         第个参数记住用this即可 ,这么理解,他就是一个句柄,
43         给别人握的, 这个句柄对象需要实现InvocationHandler接口*/
44         return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),
45             this.targetObject.getClass().getInterfaces(),this);
46     }
47     
48     
49     @Override
50     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
51         
52         pre();//前置处理
53         Object result = null;
54         result = method.invoke(this.targetObject,args);
55         after();//后置处理
56         return result;
57     }
58     
59     private void pre() {
60         System.out.println("前置");
61     }
62     
63     private void after() {
64         System.out.println("后置");
65     }
66     
67     public static void main(String[] args) {
68         JDKProxySubject factory = new JDKProxySubject();//创建工厂
69         Subject proxySubject = (Subject)factory.createProxyInstance(new RealSubject());
70         proxySubject.request();
71     }
72 }

 

结果同1

这个例子中,首先请关注下Subject处, 上一个例子中Subject是抽象类(换成接口也可以),但是这个例子中,只能使用接口。因为由createProxyInstance

方法生成的代理对象,实际上是Proxy类的一个子类,所以这里向上转型时Subject为接口才适合。使用这种方式,要求提前知道接口信息即可。

 

3.使用工具CGlib实现动态代理,需要导入cglib的jar

 1 package com.test;
 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 CGlibProxyFactory implements MethodInterceptor{
10     private Object targetObject;
11     
12     public Object createProxyInstance(Object targetObject) {
13         pre();
14         this.targetObject = targetObject;
15         Enhancer enhance = new Enhancer();//创建一个类
16         enhance.setSuperclass(this.targetObject.getClass());//非final方法进行覆盖
17         enhance.setCallback(this);//设置回调为本身
18         after();
19         return enhance.create();
20     }
21     
22     private void pre() {
23         System.out.println("前置");
24     }
25     
26     private void after() {
27         System.out.println("后置");
28     }
29     
30     
31     @Override
32     public Object intercept(Object proxy, Method method, Object[] args,
33             MethodProxy arg3) throws Throwable {
34         
35         Object result = null;
36         result = method.invoke(this.targetObject, args);
37         return result;
38     }
39     
40     public static void main(String[] args) {
41         CGlibProxyFactory factory = new CGlibProxyFactory();
42         Subject subject = (Subject)factory.createProxyInstance(new RealSubject());
43         subject.request();
44     }
45 }

 

结果同1

使用CGlib的方式,跟上一种Proxy的方式相比,甚至连接口都不需要提前知道。(性能差点)

 

三、关于代理模式和另几个模式之前的关系

1.代理模式和适配器模式:粗看上去它们都可以视为一个对象提供一种前置的接口,但是适配器模式的用意在于要改变所使用的接口,而代理模式并不能改变对象的接口。

2.代理模式和装饰模式:装饰模式是要为所装饰的对象增强功能,而代理模式是对对象的使用施加控制。

 

四(2)、复用类补充之关于代理模式的一点理解

标签:

原文地址:http://www.cnblogs.com/kaiguoguo/p/4678425.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!