GOF23设计模式之代理模式(proxy)
一、代理模式概述
1、代理模式的核心作用
(1)通过代理,控制对象的访问;
(2)可以详细的控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。(AOP的微实现)
代理模式是 AOP(Aspect Oriented Programming 面向切面编程)的核心实现机制。
2、代理模式的核心角色
(1)抽象角色
定义代理角色和真实角色的公共对外方法。
(2)真实角色
实现抽象角色,定义真实角色所需要实现的业务逻辑,供代理角色调用。
关注真正的业务逻辑。
(3)代理角色
实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑辅方法来实现抽象方法,并附加自己的操作。
将统一的流程控制放在代理角色中处理!
3、代理模式的使用场景
(1)安全代理: 屏蔽对真实角色的访问;
(2)通过代理类处理远程方法调用(RMI Remote Method Invocation 远程方法调用);
(3)延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。
4、代理模式的分类
(1)静态代理(静态定义代理类)
(2)动态代理(动态生成代理类)
① JDK自带的动态代理
② javassist字节码操作库实现
③ CGLIB
CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。
通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。
④ ASM底层使用指令,可维护性较差
ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。
二、代理模式之静态代理
示例代码场景:周杰伦开演唱会时,面谈、签合同、订票等操作都是由周杰伦的经纪人来完成,唱歌部分由他本人完成,最后收款也是由经纪人来完成。
(1)创建抽象角色
1 /** 2 * 抽象角色 3 * @author CL 4 * 5 */ 6 public interface Star { 7 /** 8 * 面谈 9 */ 10 void confer(); 11 /** 12 * 签合同 13 */ 14 void signConstract(); 15 /** 16 * 订票 17 */ 18 void bookTicket(); 19 /** 20 * 唱歌 21 */ 22 void sing(); 23 /** 24 * 收款 25 */ 26 void collectMoney(); 27 }
(2)定义真实角色
1 /** 2 * 真实身份(相当于例子中的周杰伦本人) 3 * @author CL 4 * 5 */ 6 public class RealStar implements Star { 7 8 @Override 9 public void confer() { 10 System.out.println("周杰伦去面谈"); 11 } 12 13 @Override 14 public void signConstract() { 15 System.out.println("周杰伦去签合同"); 16 } 17 18 @Override 19 public void bookTicket() { 20 System.out.println("周杰伦去订票"); 21 } 22 23 @Override 24 public void sing() { 25 System.out.println("周杰伦去唱歌"); 26 } 27 28 @Override 29 public void collectMoney() { 30 System.out.println("周杰伦去收款"); 31 } 32 33 }
(3)定义代理角色
1 /** 2 * 代理身份(相当于例子中的周杰伦的经纪人) 3 * @author CL 4 * 5 */ 6 public class ProxyStar implements Star { 7 private Star star; 8 9 public ProxyStar(Star star) { 10 this.star = star; 11 } 12 13 @Override 14 public void confer() { 15 System.out.println("经纪人去面谈"); 16 } 17 18 @Override 19 public void signConstract() { 20 System.out.println("经纪人去签合同"); 21 } 22 23 @Override 24 public void bookTicket() { 25 System.out.println("经纪人去订票"); 26 } 27 28 @Override 29 public void sing() { 30 star.sing(); 31 } 32 33 @Override 34 public void collectMoney() { 35 System.out.println("经纪人去收款"); 36 } 37 38 }
(4)测试
1 /** 2 * 客户端 3 * 只和经纪人联系 4 * @author CL 5 * 6 */ 7 public class Client { 8 9 public static void main(String[] args) { 10 Star real = new RealStar(); 11 Star proxy = new ProxyStar(real); 12 13 //面谈 14 proxy.confer(); 15 //签合同 16 proxy.signConstract(); 17 //订票 18 proxy.bookTicket(); 19 //唱歌 20 proxy.sing(); 21 //收款 22 proxy.collectMoney(); 23 } 24 }
控制台输出:
经纪人去面谈
经纪人去签合同
经纪人去订票
周杰伦去唱歌
经纪人收款
三、代理模式之动态代理
JDK自带的动态代理:
① 在客户端,java.lang.reflect.Proxy
作用:动态生成代理类和对象
② 实现java.lang.reflect.InvocationHandler(处理器接口)
可以通过invoke方法实现对真实角色的代理访问
每次通过Proxy生成代理类对象时都要指定对应的处理器对象
(1)创建抽象角色
1 public interface Star { 2 /** 3 * 面谈 4 */ 5 void confer(); 6 /** 7 * 签合同 8 */ 9 void signConstract(); 10 /** 11 * 订票 12 */ 13 void bookTicket(); 14 /** 15 * 唱歌 16 */ 17 void sing(); 18 /** 19 * 收款 20 */ 21 void collectMoney(); 22 }
(2)创建真实角色
1 /** 2 * 真实身份(相当于例子中的周杰伦本人) 3 * @author CL 4 * 5 */ 6 public class RealStar implements Star { 7 8 @Override 9 public void confer() { 10 System.out.println("周杰伦去面谈"); 11 } 12 13 @Override 14 public void signConstract() { 15 System.out.println("周杰伦去签合同"); 16 } 17 18 @Override 19 public void bookTicket() { 20 System.out.println("周杰伦去订票"); 21 } 22 23 @Override 24 public void sing() { 25 System.out.println("周杰伦去唱歌"); 26 } 27 28 @Override 29 public void collectMoney() { 30 System.out.println("周杰伦去收款"); 31 } 32 33 }
(3)创建代理角色的处理器
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 4 /** 5 * 代理角色的处理类 6 * jdk自带的动态代理 7 * @author CL 8 * 9 */ 10 public class StarHandler implements InvocationHandler { 11 private Star realStar; 12 13 public StarHandler(Star realStar) { 14 this.realStar = realStar; 15 } 16 17 //通过invoke方法实现对真实角色的代理访问 18 @Override 19 public Object invoke(Object proxy, Method method, Object[] args) 20 throws Throwable { 21 Object obj = null; 22 23 System.out.print("在执行真实角色的方法之前的处理,比如-->"); 24 System.out.println("面谈,签合同,订票"); 25 26 if (method.getName().equals("sing")) { 27 obj = method.invoke(realStar, args); 28 } 29 30 System.out.print("在执行真实角色的方法之后的处理,比如-->"); 31 System.out.println("收款"); 32 33 return obj; 34 } 35 36 }
(4)测试
1 import java.lang.reflect.Proxy; 2 3 /** 4 * 测试JDK自带的动态代理 5 * @author CL 6 * 7 */ 8 public class Client { 9 10 public static void main(String[] args) { 11 Star realStar = new RealStar(); 12 13 StarHandler handler = new StarHandler(realStar); 14 15 Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class}, handler); 16 17 proxy.sing(); 18 } 19 }
控制台输出:
在执行真实角色的方法之前的处理,比如-->面谈,签合同,订票
周杰伦去唱歌
在执行真实角色的方法之后的处理,比如-->收款