在生活中,我们经常见到这样的场景,如:租房中介、售票黄牛、婚介、经纪人、快递、事务代理、非侵入式日志监听等,这些都是代理模式的实际体现。代理模式(Proxy Pattern)的定义也非常简单,是指为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客服端和目标对象之间起到中介作用,代理模式属于结构型设计模式。使用 代理模式主要有两个目的:一保护目标对象,二增强目标对象。下面我们来看一下代理模式的类结构图: Subject 是顶层接口,RealSubject 是真实对象(被代理对象),Proxy 是代理对象,代理对象持有被代理对象的引用,客户端调用代理对象方法,同时也调用被代理对象的方 法,但是在代理对象前后增加一些处理。在代码中,我们想到代理,就会理解为是代码增强,其实就是在原本逻辑前后增加一些逻辑,而调用者无感知。代理模式属于结构型 模式,有静态代理和动态代理。
举个例子:人到了适婚年龄,父母总是迫不及待希望早点抱孙子。而现在社会的人在各种压力之下,都选择晚婚晚育。于是着急的父母就开始到处为自己的子女相亲,比子女 自己还着急。这个相亲的过程,就是一种我们人人都有份的代理。来看代码实现:
public interface Person { void findLove(); } public class Son implements Person { @Override public void findLove() { System.out.println("儿子要求: 上海名媛"); } } public class Father implements Person { private Son son; public Father(Son son) { this.son = son; } @Override public void findLove() { System.out.println("父母物色对象"); son.findLove(); System.out.println("双方同意交往,确立关系"); } } public class Test { public static void main(String[] args) { Father father=new Father(new Son()); father.findLove(); } }动态代理和静态对比基本思路是一致的,只不过动态代理功能更加强大,随着业务的扩展适应性更强。如果还以找对象为例,使用动态代理相当于是能够适应复杂的业务场景。不仅仅只是父亲给儿子找对象,如果找对象这项业务发展成了一个产业,进而出现了媒婆、婚介所等这样的形式。那么,此时用静态代理成本就更大了,需要一个更加通用的解决方案,要满足任何单身人士找对象的需求。我们升级一下代码,先来看 JDK 实现方式:
使用JDK的java.lang.reflect.Proxy类的newProxyInstance方法实现动态代理:
public interface Person { void findLove(); } public class Customer implements Person { @Override public void findLove() { System.out.println("上海名媛"); } } public class JdkMeiPoInvocationHandler implements InvocationHandler { private Object target; public Object getInstance(Object target) { this.target = target; Class<?> clazz = target.getClass(); return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object obj = method.invoke(target, args); after(); return obj; } private void before(){ System.out.println("我是媒婆:我要给你找对象,现在已经拿到你的需求"); } private void after(){ System.out.println("如果合适的话,就准备办事"); } } public class JdkTest { public static void main(String[] args) { Person person= (Person) new JdkMeiPoInvocationHandler().getInstance(new Customer()); person.findLove(); } }(1) 静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步新增,违背开闭原则。 (2) 动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则。 (3) 若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成,无需修改代理类的代码。
使用代理模式具有以下几个优点: (1) 代理模式能将代理对象与真实被调用的目标对象分离。 (2) 一定程度上降低了系统的耦合度,扩展性好。 (3) 可以起到保护目标对象的作用。 (4) 可以对目标对象的功能增强
缺点: (1) 代理模式会造成系统设计中类的数量增加。 (2) 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。 (3) 增加了系统的复杂度。