干我们这行,啥时候懈怠,就意味着长进的停止,长进的停止就意味着被淘汰,只能往前冲,直到凤凰涅槃的一天! 博客园 新随笔 管理 随笔-126 评论-286 文章-0
Java设计模式之代理模式(Proxy)
前言:
最近在研究Retrofit开源框架的时候,其主要核心代码是通过注解标示参数,动态代理模式实现具体接口,反射机制进行参数解析,最终实现发送请求。其实之前在学习Xutils源码的时候,Xutils 的task也是通过代理模式来访问的。为何要采用代理模式呢?有什么好处呢?抱着这些疑问!今天来学习总结一下。
什么是代理模式?
代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。举例说明,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。
应用场景举例:
通过上面的代理模式描述我们可以知道,其目的就是为了控制对象引用,生活场景中我们以买车为例,如果我们要买一辆轿车必须通过汽车4S店,汽车4s店就是充当代理角色,其目的就是控制买车客户的买车行为,必须通过汽车4S店才能从汽车厂商买一辆车。
1.)首先新建一个买车的接口
public interface IBuyCar {
//买车
void buyCar();
}
2.)声明一个要买车的客户,实现买车接口
public class Customer implements IBuyCar {
private int cash;//购车款
public int getCash() {
return cash;
}
public void setCash(int cash) {
this.cash = cash;
}
@Override
public void buyCar() {
Log.e("buyCar", "买一辆车花费了-->" + cash + "元");
}
}
3.)声明一个买车代理汽车4S店,同样也实现买车接口,必须接受客户下单
public class BuyCarProxy implements IBuyCar{
private Customer customer;//接收买车客户
public BuyCarProxy(Customer customer){
this.customer=customer;//接收买车客户
}
@Override
public void buyCar() {//实现为客户买车
customer.buyCar();
}
}
4.)创建一个客户端,模拟一次买车
Customer customer=new Customer();
customer.setCash(120000);
BuyCarProxy buyCarProxy=new BuyCarProxy(customer);
buyCarProxy.buyCar();

5.)通过代理模式实现权限控制
通过上面的例子,我们可能有个疑问,难道就不能直接去厂家买车吗?当然可以,如果在使用场景中实现类能满足要求时,我们当然可以直接实现类,但当实现类不能满足要求,要扩展需求,根据开闭原则你又不能修改实现类代码,这时你就用代理类。比如购买一辆车我们要对客户进行一个购车款审核,如果符合条件就买车,不符合要求我们就告知客户购车款不足。
@Override
public void buyCar() {//实现为客户买车
int cash=customer.getCash();
if(cash<100000){
Log.e("buyCar","你的钱不够买一辆车");
return;
}
customer.buyCar();
}
实现场景
Customer customer=new Customer();
customer.setCash(120000);
BuyCarProxy buyCarProxy=new BuyCarProxy(customer);
buyCarProxy.buyCar();
Customer customer1 =new Customer();
customer1.setCash(90000);
BuyCarProxy buyCarProxy1 =new BuyCarProxy(customer1);
buyCarProxy1.buyCar();

动态代理机制:
以上讲的都是代理模式的静态实现,所谓静态代理就是自己要为要代理的类写一个代理类,或者用工具为其生成的代理类,总之,就是程序运行前就已经存在的编译好的代理类,这样有时候会觉得非常麻烦,也导致非常的不灵活,相比静态代理,动态代理具有更强的灵活性,因为它不用在我们设计实现的时候就指定某一个代理类来代理哪一个被代理对象,我们可以把这种指定延迟到程序运行时由JVM来实现。
举例:还是接着上面的例子
1.)首先我们要声明一个动态代理类,实现InvocationHandler接口
public class DynamicProxy implements InvocationHandler {
// 被代理类的实例
Object obj;
// 将被代理者的实例传进动态代理类的构造函数中
public DynamicProxy(Object obj) {
this.obj = obj;
}
/**
* 覆盖InvocationHandler接口中的invoke()方法
* 更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构
* 的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到
* 控制被代理对象的行为,下面的before、after就是我们可以进行特殊
* 代码切入的扩展点了。
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*
* before :doSomething();
*/
Object result = method.invoke(this.obj, args);
/*
* after : doSomething();
*/
return result;
}
}
2.)具体实现
//我们要代理的真实对象
Customer customer = new Customer();
//我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new DynamicProxy(customer);
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数customer.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
IBuyCar buyCar = (IBuyCar) Proxy.newProxyInstance(handler.getClass().getClassLoader(), customer.getClass().getInterfaces(), handler);
buyCar.buyCar();
3.)动态代理好处
使用Java动态代理机制的好处:
1、减少编程的工作量:假如需要实现多种代理处理逻辑,只要写多个代理处理器就可以了,无需每种方式都写一个代理类。
2、系统扩展性和维护性增强,程序修改起来也方便多了(一般只要改代理处理器类就行了)。
总结:
通过上面的应用例子我们学习了代理模式的具体使用场景。
干我们这行,啥时候懈怠,就意味着长进的停止,长进的停止就意味着被淘汰,只能往前冲,直到凤凰涅槃的一天! posted on 2016-07-22 10:50 总李写代码 阅读(16545) 评论(2) 编辑 收藏评论: #1楼 2018-04-27 17:33 | frankie0802
假如需要实现多种代理处理逻辑,只要写多个代理处理器就可以了
请问怎么写多个代理处理器呢?谢谢了 支持(0)反对(0) #2楼 39692442018/5/7 16:38:03 2018-05-07 16:38 | uidoer
@ frankie0802
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /* DynamicProxy : 动态代理类名。 如果你想另外第一个别的动态代理类去做别的事情,同样地,也必须要实现InvocationHandler 接口。 */ public class DynamicProxy implements InvocationHandler { // 被代理类的实例 Object obj; // 将被代理者的实例传进动态代理类的构造函数中 public DynamicProxy(Object obj) { this.obj = obj; } /** * 覆盖InvocationHandler接口中的invoke()方法 * 更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构 * 的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到 * 控制被代理对象的行为,下面的before、after就是我们可以进行特殊 * 代码切入的扩展点了。 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /* * before :doSomething(); //动态代理类为目标类额外做的前置方法 * 可以是简单的sysout。也可以是你具体的方法 */ Object result = method.invoke(this.obj, args); /* * after : doSomething(); //动态代理类为目标类额外做的后置方法 * 可以是简单的sysout。也可以是你具体的方法 */ return result; } } |
【前端】SpreadJS表格控件,可嵌入应用开发的在线Excel
【推荐】如何快速搭建人工智能应用?
【活动】AI技术全面场景化落地实践
【大赛】2018首届“顶天立地”AI开发者大赛
最新IT新闻:· Google Photos面部识别功能获更新:将同个人照片整合至一个组
· Facebook最大的问题是什么?高管们都不会说话
· 爱钱帮出借合同曝疑点:陆复斌、张培峰唱“双簧”?
· NASA下周五公布执行SpaceX及波音太空载人飞行任务宇航员名单
· Python之父透露退位隐情,与核心开发团队产生隔阂
» 更多新闻...
最新知识库文章:· 历史转折中的“杭派工程师”
· 如何提高代码质量?
· 在腾讯的八年,我的职业思考
· 为什么我离开了管理岗位
· 那些让人睡不着觉的bug,你有没有遭遇过?
» 更多知识库文章... 昵称:总李写代码
园龄:2年2个月
粉丝: 365
关注:0 +加关注
最新随笔
- 1. Android学习探索之App多渠道打包及动态添加修改资源属性
- 2. Android学习探索之运用MVP设计模式实现项目解耦
- 3. Android注解使用之Dagger2实现项目依赖关系解耦
- 4. Android学习探索之本地原生渲染 LaTeX数据公式
- 5. Java数据结构之Set学习总结
- 6. Java数据结构之Map学习总结
- 7. Java数据结构之LinkedList、ArrayList的效率分析
- 8. Android业务组件化之Gradle和Sonatype Nexus搭建私有maven仓库
- 9. Android UI体验之全屏沉浸式透明状态栏效果
- 10. Android注解使用之通过annotationProcessor注解生成代码实现自己的ButterKnife框架
随笔分类(126)
- Android UI体验(1)
- Android动画效果(5)
- Android混合开发(3)
- Android加密解密(7)
- Android权限管理(3)
- Android使用注解(5)
- Android数据存储(5)
- Android四大组件(4)
- Android图片缓存(4)
- Android网络请求(6)
- Android线程管理(5)
- Android消息传递(4)
- Android性能优化(5)
- Android学习探索(4)
- Android业务组件化(4)
- Android音频视频(5)
- Android知识小结(3)
- Android自定义控件(4)
- Hybrid App开发(10)
- IOS缓存管理(2)
- IOS控件布局(5)
- IOS任务管理(3)
- IOS数据存储(6)
- IOS网络请求(2)
- IOS学习总结(6)
- Java日常总结(3)
- Java设计模式(6)
- Java数据结构(3)
- React Native开发
- 工作随笔(3)
积分与排名
- 积分 - 274375
- 排名 - 780
最新评论
- 1. Re:Android探索之HttpURLConnection网络请求
- // 设置为Post请求
urlConn.setRequestMethod("GET"); - --梦书
- 2. Re:Android数据加密之Rsa加密
- @bitera答案参差不齐,RSA的单独使用和RSA与AES的配套使用的性能区别,以及验证代码。为什么配套使用就性能高?不理解...
- --messagepool
- 3. Re:Android消息传递之Handler消息机制
- 啥也不懂得我只能敲66666
- --曾涤先生
阅读排行榜
- 1. Android图片缓存之初识Glide(62804)
- 2. Android消息传递之EventBus 3.0使用详解(58951)
- 3. Android okHttp网络请求之Get/Post请求(56570)
- 4. Android数据存储之GreenDao 3.0 详解(54189)
- 5. Android okHttp网络请求之文件上传下载(45683)
- 6. Android自定义控件之基本原理(40933)
- 7. Android自定义控件之自定义组合控件(40004)
- 8. Android数据加密之MD5加密(32836)
- 9. Android数据加密之Base64编码算法(30479)
- 10. Android混合开发之WebView与Javascript交互(28913)
- 11. Android图片缓存之Glide进阶(28723)
- 12. Android业务组件化之URL Scheme使用(28515)
- 13. Android数据加密之Aes加密(26565)
- 14. Android线程管理之Thread使用总结(24671)
- 15. Java设计模式之模板模式(Template )(24038)
- 16. Android动画效果之Frame Animation(逐帧动画)(22381)
- 17. Android混合开发之WebView使用总结(21543)
- 18. Android注解使用之ButterKnife 8.0注解使用介绍(20226)
- 19. Android探索之HttpURLConnection网络请求(19649)
- 20. Android自定义控件之自定义属性(19469)
推荐排行榜
- 1. Android自定义控件之自定义组合控件(11)
- 2. Android业务组件化之URL Scheme使用(8)
- 3. Android业务组件化之现状分析与探讨(7)
- 4. Android自定义控件之基本原理(7)
- 5. Android注解使用之ButterKnife 8.0注解使用介绍(6)
- 6. Android okHttp网络请求之Get/Post请求(6)
- 7. Android图片缓存之初识Glide(5)
- 8. Android UI体验之全屏沉浸式透明状态栏效果(5)
- 9. Android混合开发之WebViewJavascriptBridge实现JS与java安全交互(5)
- 10. Android数据存储之GreenDao 3.0 详解(5)
- 11. Android动画效果之初识Property Animation(属性动画)(5)
- 12. Android消息传递之EventBus 3.0使用详解(4)
- 13. Java学习之反射机制及应用场景(4)
- 14. Android性能优化之利用LeakCanary检测内存泄漏及解决办法(4)
- 15. Java设计模式之模板模式(Template )(4)
- 16. Android混合开发之WebView与Javascript交互(3)
- 17. IOS缓存管理之YYCache使用(3)
- 18. Android线程管理之ThreadPoolExecutor自定义线程池(3)
- 19. Android混合开发之WebView使用总结(3)
- 20. Android数据加密之Aes加密(3)