说到代理你首选会想到什么:
不方便自己做的事,要不要找个代理?比如说:美国人的代理人战争
自己搞不定或者不擅长的事,要不要找个代理?比如说:代汽车上牌、房产中介、黄牛等;
没错,这就是代理。当然这篇文章主要是来盘一盘设计模式中的代理模式。
代理模式是一种设计模式,它为其他对象提供一种代理以控制对该对象的访问。即用户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。代理模式给某一个对象提供一个代理对象,并由代理对象控制原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。通过代理类,起到了中介隔离作用,代理类除了是客户类和委托类的中介隔离作用之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类,而不需要在修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转达给委托类,以及时候对返回结果的处理等。代理类本身不真正实现服务,而是通过调用委托类的相关方法,来提供特定的服务。例如,购买火车票不一定要去火车站买,可以通过 12306 网站或者去火车票代售点买。又比如找女朋友、找保姆、找工作等都可以通过找中介完成
代理模式有四个核心角色,UML类图与详细介绍如下:
根据代理的创建时期,代理模式分为静态代理和动态代理。
水浒传相信很多人都看过,这里就以西门庆通过王婆与潘金莲私会的情节举个例子,在这个情节中,王婆实际上都是充当一个代理人的角色,自己本身并不执行约会这件事,实际执行约会这件事的人是金莲;当然了,每次西门庆想与金莲玩耍一番,不会直接上金莲家的,而是到王婆家中,给王婆交上几两银子,然后王婆再把金莲叫来,一番玩耍后,王婆还会再假模假样的客气一番:“官人再来”之类的话。
如果画一个UML类图来表示这件事的话,如下:
代码示例:
1、定义抽象的约会类(抽象主题);
2、 定义金莲(真实的主题);
3、定义王婆(代理);
4、定义西门庆(客户端);
- /**
- * 约会
- */
- public interface YueHui {
- /**
- * 玩耍
- */
- void play();
- }
- /**
- * 金莲
- */
- public class PanJinLian implements YueHui{
- @Override
- public void play() {
- System.out.println("金莲:玩得很开心呢");
- }
- }
- /**
- * 王婆
- */
- public class WangPo implements YueHui {
- private PanJinLian panJinLian;
-
- public WangPo(PanJinLian panJinLian) {
- this.panJinLian = panJinLian;
- }
-
- @Override
- public void play() {
- this.beforePlay();
- panJinLian.play();
- this.afterPlay();
- }
-
- private void beforePlay(){
- System.out.println("王婆:交五两银子");
- }
-
- private void afterPlay(){
- System.out.println("王婆:欢迎下次再来");
- }
- }
- /**
- * 西门庆
- */
- public class XiMenQing {
- public static void main(String[] args) {
- PanJinLian panJinLian = new PanJinLian();
- WangPo wangPo = new WangPo(panJinLian);
- wangPo.play();
- }
- }
动态代理:是在程序运行时,运用反射机制动态创建而成,从实现上又分为两类:
这里主要分享一下JDK动态代理这种方式,另一种方式有兴趣的小伙伴可以自行再拓展一下。
还是上面的例子,用Java的动态代理再来实现一下;其实也很简单,上面的静态代理对象WangPo是在代码编译前已经实现好的,这里的动态代理对象panJinLianProxy则是通过Proxy类使用Java反射技术在程序运行时动态生成的;
- public class WangPoHandler implements InvocationHandler {
- private PanJinLian panJinLian;
-
- public WangPoHandler(PanJinLian panJinLian) {
- this.panJinLian = panJinLian;
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- this.beforePlay();
- Object result = method.invoke(panJinLian, args);
- this.afterPlay();
- return result;
- }
- private void beforePlay() {
- System.out.println("王婆:交五两银子");
- }
- private void afterPlay() {
- System.out.println("王婆:欢迎下次再来");
- }
- }
- public class XiMenQing2 {
- public static void main(String[] args) {
- PanJinLian panJinLian = new PanJinLian();
- WangPoHandler wangPoHandler = new WangPoHandler(panJinLian);
- YueHui panJinLianProxy = (YueHui) Proxy.newProxyInstance(WangPoHandler.class.getClassLoader(), PanJinLian.class.getInterfaces(), wangPoHandler);
- panJinLianProxy.play();
- }
- }
在Spring框架中,代理模式应用场景如下:
但是需要注意的是,Spring中的代理模式主要有两种实现方式:基于JDK的动态代理和基于CGLib的动态代理。其中,基于JDK的动态代理主要依赖于Java反射机制,通过为每个需要代理的类生成一个子类来实现代理;而基于CGLib的动态代理则通过在运行时创建子类来实现代理。