代理模式
Proxy Pattern:代理模式是GoF23中设计模式中,属于结构型模式的一种。
关于代理模式的定义官方给出的是:为其他对象提供一种代理以控制对这个对象的访问(好像也是可以理解一点儿的吧。)
笔者自己的理解方式呢,代理,代理嘛,用个不恰当的比喻来说的话,哈哈,那就是叫家长啊,有木有,老师们的终极绝招之一啊,怎么说呢,就是老师要叫家长的需要通知我们自己,然后让我们回家去把自己的老爸啊老妈叫过来,或者老师直接一个电话打到你的家里去,打到你老爸老妈的手机上,对吧!
PS: 这里呢,需要注意,注意了,可以发现,老师是没有办法直接找到你的老爸老妈当着面说的(当然,如果你就住在你老师家的旁边的话,那就,嘿嘿嘿)。这里我们可以把我们自己或者手机这两个现实对象呢抽象成为代理了,而我们的老爸老妈呢,那就是真实的对象,而老师呢,那就是用户了。
也就是说,用户(也就是老师啊)想要访问(嗯,就是找了)真实的对象(我们滴家长)是需要中间过程的(比如我们回家的传话,或者打电话)也就是需要通过代理(例如手机)才能去访问真实的对象。
结构
简单的分析一下代理模式的类图,可以看到有三个对象角色:
- 抽象对象:这个不用说,面向接口编程,抽象是不可避免的,是真实对象和代理对象的直接抽象。
- 真实对象:抽象对象的具体实现类。
- 代理对象:这个需要说一说,这个代理对象应该是和真实对象长得极为相似的,唯一不同的就是代理对象之中要包含一个真实对象的实例。这是为什么呢?可以看一下代理模式的定义,代理对象是需要控制外部对真实对象的访问的,既然真实的对象需要被访问,那么真实的对象的所用功能在代理对象中都要被看得见,摸得着的,如果代理对象说这个方法可以让真实对象执行了,这个时候代理对象是需要调用真实对象的方法的。
举例说明
- 代理模式的思想的使用很多很多,比如我们熟悉的VPN代理(现在的笔者是不能白嫖Youtube了,老老实实买流量的),由或者我们的防火墙?
- 火热的Spring框架的除了核心IoC之外,还有一个AOP,这个面向方面编程的东西也是基于代理模式的,CGLIB的动态代理哦。
- Zuul网关服务,也是代理模式思想的体现呢。
- 贴近生活一点的,代理的体现还真有这一群人,他们的职业叫做经纪人啊,还有就是笔者之前找房子租的时候的中介商也是代理。
注意
- 在JAVA中关于代理的实现有三种方式:
- 一种是直接代码实现的静态代理;
- 一种是通过JDK实现的动态代理;
- 还有一种是CGLIB实现的动态代理,这是一个对JDK实现方式的优化。
- 解释一下静态代理和动态代理呀
- 静态代理:在程序运行前就以及存在了的,已经是完完全全成熟的代码,可以拿来就用的,用个不恰当的比喻——比如一个类的静态变量,这个类一加载,这个静态变量就可以访问了。
- 动态代理:这就是只有在运行阶段才指定到底代理啥子东西的,再用个不恰当的比喻——比如类的实例成员,类加载了也访问不了,只有创建了类的实例了之后,才调用它才会可以使用。
- 代理模式的使用优点很明显,首先呢就是高扩展性,其次就是代理将用户和真实对象完全分开,这样子的安全性也得到了提高,最后呢也就是明确定义的各个对象的职责了,代理对象呢只管用户的调用来决定能不能成,而真实对象呢,自己实现自己的东西就可以了,有没有人找它也不用担心,反正有代理呢不是!
- 有了优点,缺点也是有一点的,比较明显的就是慢了一点,额,原因嘛就是多了一个中转,用户到真实对象中间夹着一个代理,发出了两次请求,没有的话,那就是一步到位,自然是慢了一点,但是处于安全性的考虑,代理模式还是很不错的。
一个小DEMO
-
场景
这次的小DEMO呢,就用笔者不久前租房子的例子来吧。这里的真实对象不是房东啊(我也没看到房东,房东似乎完全放权给了这个租房的平台唉),那真实对象就是房子吧,也是中介们口中的房源。而用户呢就是笔者自己了,代理对象就是中介啦。
-
先定义后抽象对象(这里就直接用接口了)
package com.proxy; /** * 代理模式——抽象对象 * 这个DEMO中,我就抽象成大HOUSE * @author WQ */ public interface House { /** * 简单的方法用于测试 */ void show(); }
-
弄个真实对象
package com.proxy; /** * 代理模式——真实对象 * 一个人嘛,单人间咯(似乎有点淡淡的忧伤~~~) * @author WQ */ public class SingleRoom implements House{ @Override public void show() { System.out.println("我这个单人间就租给你了!"); } }
-
代理对象上场
package com.proxy; /** * 代理模式——代理对象 * 中介小姐姐 * @author WQ */ public class Intermediary implements House{ // 手里有着房源啊,不然怎么给别人租呢? private House house; /** * 实现多态吧,这个位置, * 其实可以直接定义SingleRoom类也是没有关系的在这个例子里面 * @param house 房源抽象对象 */ public Intermediary(House house) { this.house = house; } /** * 这个方法在真实对象中也有,注意啊, * 代理对象是控制外部(也就是用户)对真实对象的调用的 * 是可以控制的啊,控制的 */ @Override public void show() { /** * 这是调用的真实对象的方法 */ house.show(); } /** * 我们将这个方法暴露给用户, * 当然也可以直接在上面show方法中进行控制, * 这里不改变完整的结构,重新起一个方法来实现 * @param price 价格 */ public void rent(double price) { if (price < 10000.00) { System.out.println("啥?你没这么多钱?那走吧,走吧,我们看下一个~~~"); return;//直接返回了,有木有,和真实对象没有任何关系哦 }else { System.out.println("可以接受?那好说啊!"); /** * 注意啊,这个位置才是调用了方法的哦 */ show(); } } }
-
测试类
package com.proxy; /** * 代理模式——测试类 * @author WQ */ public class Main { public static void main(String[] args) { //代理对象,对房源进行代理 Intermediary intermediary = new Intermediary(new SingleRoom()); //用户看房了,看了看,不咋样,给个8000一个季度吧,叫来中介小姐姐说了个价格 intermediary.rent(8000.00); System.out.println(); //哎呦,又看了一个,这个倒是不错,12000一个季度吧,有一次叫来中介小姐姐 intermediary.rent(12000.00); } }
-
测试走一泼
啥?你没这么多钱?那走吧,走吧,我们看下一个~~~ 可以接受?那好说啊! 我这个单人间就租给你了!
完成!