一、代理模式的作用:将主要业务和次要业务进行松耦合组装
何时使用:想在访问一个类时做一些控制
代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象
代理(Proxy)是一种设计模式,定义:为其他对象提供一个代理以控制对某个对象的访问,即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法
解决的问题: 防止直接访问目标对象给系统带来的不必要复杂性
二、生活案例:
1.饭前便后要洗手
主要业务:吃饭;上厕所;
次要业务:洗手;
2、jdk代理模式的实现:
2.1接口角色:定义所有需要被监听的行为
2.2接口实现类:中国人,法国人
2.3通知类:
1)次要业务具体实现
2)通知JVM,当前被拦截的主要业务与次要业务应该如何绑定执行
2.4监控对象(代理对象):
1)被监控实例对象
2)需要被监控行为
3)具体通知类实例对象
三、代码案例(以饭前便后要洗手为例)
|
代码实现:
1.创建需要被监控行为的接口
/* * 只有需要被监控的行为才有资格在这里声明 **/ public interface BaseService { void eat(); void wc(); }
2.创建主要业务实现被监控行为
public class Person implements BaseService{ //主要业务,代理模式要求开发人员只关心主要业务 @Override public void eat() { System.out.println("eating......"); } @Override public void wc() { System.out.println("wc......"); } }
3.创建监控类(通知类),监控需要执行对象的行为
public class Invocation implements InvocationHandler { // 具体被监控对象 private BaseService baseService; public Invocation(BaseService baseService) { this.baseService = baseService; } /* * * invoke方法:在被监控行为将要执行时,会被JVM拦截 被监控行为和行为实现方会被作为参数输送invoke * ****通知JVM,这个被拦截方法是如何与当前次要业务方法绑定实现 invoke方法三个参数 * * int v= 小明.eat();//JVM拦截 method:eat方法封装为Mehtod类型对象 * params:eat方法运行时接受所有的实参封装到Object[] proxy:将负责监控小明的代理对象作为invoke方法第一个参数 * */ // 通知JVM,当前被拦截的主要业务与次要业务应该如何绑定执行 @Override public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { // 0.局部变量,接受主要业务方法执行完毕后返回值 Object value; // 1.确认当前被拦截行为 String methodName = method.getName(); // 2.根据被拦截行为,决定主要业务和次要业务如何绑定执行 if ("eat".equals(methodName)) { // 饭前先洗手 wash(); value = method.invoke(this.baseService, params); } else { // 便后要洗手 value = method.invoke(this.baseService, params); wash(); } // 3.返回被拦截的方法 return value; } // 次要业务具体实现 private void wash() { System.out.println("---洗手---"); } }
4.创建代理对象,通过代理对象来对我们不同的目标对象(如person,animal),将大家都需要的次要业务和主要业务进行绑定输出。
这里通过代理对象,可以在person功能(吃饭,上厕所)实现的基础上,增强额外的功能(如洗手),可扩展性强。通过代理模式,不会影响主要业务,额外的功能通过代理模式实现就OK,不会修改别人的代码。
/* * * JDK动态代理模式下,代理对象的数据类型 * 应该由监控行为来描述 * 参数: Class文件,监控类 */ public class ProxyFactory { public static BaseService builder(Class<?> classFile) throws Exception { // 1.创建一个被监控实例对象 BaseService baseService = (BaseService) classFile.newInstance(); // 2.创建一个通知对象 InvocationHandler adviser = new Invocation(baseService); /* * newProxyInstance的三个参数: * loader:被监控对象隶属的类文件在内存中真实地址 * interfaces:被监控对象隶属的类文件实现接口 * h:监控对象发现小明要执行被监控行为,应该有哪一个通知对象进行辅助 */ // 3.向JVM申请负责监控baseService对象指定行为的监控对象(代理对象) BaseService $proxy = (BaseService) Proxy.newProxyInstance(baseService.getClass().getClassLoader(), baseService.getClass().getInterfaces(), adviser); return $proxy; } }
5.测试代码
public class TestMain { public static void main(String[] args) throws Exception { BaseService person = ProxyFactory.builder(Person.class); person.eat(); person.wc(); System.out.println("-----------------------------"); BaseService animal = ProxyFactory.builder(Animal.class); animal.eat(); animal.wc(); } }
输出结果: