内容简介:代理(Proxy)模式是设计模式中结构型模式的一种,即通过代理对象访问目标对象。这样做的好处是可以在目标对象实现的基础上,对目标对象进行扩展,比如增加日志打印等。现实中有很多代理模式的例子。比如过年的时候买不到火车票怎么办?找黄牛啊,这个时候黄牛就是一个代理,我们只需要和这个代理去打交道,剩下买票工作交给黄牛去做。代理模式的通用UML图如下:
定义
代理(Proxy)模式是 设计模式 中结构型模式的一种,即通过代理对象访问目标对象。这样做的好处是可以在目标对象实现的基础上,对目标对象进行扩展,比如增加日志打印等。
现实中有很多代理模式的例子。比如过年的时候买不到火车票怎么办?找黄牛啊,这个时候黄牛就是一个代理,我们只需要和这个代理去打交道,剩下买票工作交给黄牛去做。
代理模式的通用UML图如下:
涉及到以下几个角色
- Subject抽象角色:定义被代理角色和代理角色要实现接口。
- RealSubject目标角色:实现抽象角色,即具体业务逻辑。
- Proxy代理角色:实现抽象角色,持有目标角色的引用。
接下来看一下具体的代码实现:
静态代理实现
Subject抽象角色Subject.java
public interface Subject { void operation(); void operation2(); }
RealSubject目标角色RealSubject.java
public class RealSubject implements Subject { @Override public void operation() { System.out.println("我是真实操作"); } @Override public void operation2() { System.out.println("我是真实操作2"); } }
Proxy代理角色StaticProxy.java
public class StaticProxy implements Subject { private Subject realSubject; public StaticProxy(Subject subject) { this.realSubject = subject; } @Override public void operation() { System.out.println("我是代理操作"); realSubject.operation(); } @Override public void operation2() { System.out.println("我是代理操作2"); realSubject.operation(); } }
测试类Test.java
public class Test { public static void main(String args[]) { /** * 静态代理 */ Subject subject = new RealSubject(); Subject proxy = new StaticProxy(subject); proxy.operation(); proxy.operation2(); } }
打印结果
我是代理操作 我是真实操作 我是代理操作2 我是真实操作
可以看到,在真实要操作的对象前,可以输出一些我们定义好的逻辑,这就是代理模式的实现。代理模式实现的方式有几种。以上是静态代理,还有一种是动态代理,在运行时生成代理对象。接下来看一下动态代理如何实现。
动态代理实现
在 Java 中要想实现动态代理机制,需要用到java.lang.reflect.InvocationHandler和 java.lang.reflect.Proxy。
代理类要实现InvocationHandler接口,重写invoke,可以在这里对目标角色进行增强,比如这里打印了一条日志。
public class DynamicProxy implements InvocationHandler { private Object obj; public DynamicProxy(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("我是代理操作" + method.getName()); Object result = method.invoke(obj, args); return result; } }
测试类Test.java
Subject subject1 = new RealSubject(); DynamicProxy handler = new DynamicProxy(subject1); Subject proxy1 = (Subject) Proxy.newProxyInstance(subject1.getClass().getClassLoader(), subject1.getClass().getInterfaces(), handler); proxy1.operation(); proxy1.operation2();
可以看到,通过反射得到了一个代理对象,执行结果的静态代理类似,如下:
打印结果
我是代理操作operation 我是真实操作 我是代理操作operation2 我是真实操作2
小结
无论是静态代理还是动态代理,都是对被代理对象进一步的包装。
静态代理
优点:目标类无需关系代理类实现逻辑,只需知道有代理类即可。 缺点:目标类和代理类实现相同的接口,代码量变大。如果接口增加了一个方法,那么目标类和代理类都需要增加这个方法的实现。
动态代理
优点:代码量少 缺点:只能代理实现接口的类,没有实现接口的类就不能实现动态代理。通过反射会有性能消耗。
one more thing
在Android性能监控开发中,我们可能对网络库的请求进行监控,在请求之前或之后做一些统计,接下来我们就以OkHttp为例,对网络请求进行代理(当然OkHttp自己有一套拦截器机制也可以实现对请求拦截,不在我们讨论范围内)。以下例子没什么难度,但是会在接下来的文章中用到。
静态代理
一般情况下,OkHttp的请求是这样的
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().get().url("https://democome.com/").build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { Log.d(TAG, response.body().string()); } });
我们要做的就是代理Callback,在返回之前打一些日志。按照代理模式的定义实现如下:
代理类CallbackProxy
public class CallbackProxy implements Callback { public static final String TAG = CallbackProxy.class.getSimpleName(); private Callback realCallback; public CallbackProxy(Callback realCallback) { this.realCallback = realCallback; } @Override public void onFailure(Call call, IOException e) { Log.d(TAG, "请求失败先搞点事情" + e.toString()); realCallback.onFailure(call, e); } @Override public void onResponse(Call call, Response response) throws IOException { Log.d(TAG, "请求成功先搞点事情" + response.toString()); realCallback.onResponse(call, response); } }
调用 工具 类
public class StaticUtil { public static void proxyRequest(Call call, Callback callback) { CallbackProxy callbackProxy = new CallbackProxy(callback); call.enqueue(callbackProxy); } }
调用
StaticUtil.proxyRequest(call, new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) { try { Log.d(TAG, response.body().string()); } catch (IOException e) { e.printStackTrace(); } } });
动态代理
调用工具类
public class DynamicUtil { public static final String TAG = DynamicUtil.class.getSimpleName(); public static class ResponseHandler implements InvocationHandler { private Object obj; public ResponseHandler(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Log.d(TAG, "要请求了 搞事搞事搞事" + method.toString()); Object result = method.invoke(obj, args); return result; } } /** * @param call * @param callback */ public static void proxyRequest(Call call, Callback callback) { ResponseHandler handler = new ResponseHandler(callback); Callback proxy = (Callback) Proxy.newProxyInstance(callback.getClass().getClassLoader(), callback.getClass().getInterfaces(), handler); call.enqueue(proxy); } }
调用
DynamicUtil.proxyRequest(call, new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { try { Log.d(TAG, response.body().string()); } catch (IOException e) { e.printStackTrace(); } } });
demo地址:https://github.com/77Y/ProxySample
本文由 snow 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: 2019/01/04 10:04
以上所述就是小编给大家介绍的《设计模式之代理模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 设计模式——订阅模式(观察者模式)
- 设计模式-简单工厂、工厂方法模式、抽象工厂模式
- java23种设计模式-门面模式(外观模式)
- 设计模式-享元设计模式
- Java 设计模式之工厂方法模式与抽象工厂模式
- JAVA设计模式之模板方法模式和建造者模式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML5和CSS3实例教程
Brian P.Hogan / 李杰、刘晓娜、柳靖、朱嵬 / 人民邮电出版社 / 2012-1 / 39.00元
《HTML5和CSS3实例教程》共分3部分,集中讨论了HTML5和CSS3规范及其技术的使用方法。首先是规范概述,介绍了新的结构化标签、表单域及其功能(包括自动聚焦功能和占位文本)和CSS3的新选择器。接下来是HTML对视频和音频的支持,讲述了画布上的图形绘制及CSS阴影、渐变和变换的使用方法。最后介绍使用HTML5的客户端特性(包括WebStorage、WebSQLDatabases以及离线支持......一起来看看 《HTML5和CSS3实例教程》 这本书的介绍吧!