代理模式,涉及到两个角色:代理者 与 委托者,即 Proxy 与Delegator,代理者不能真正做事,真正做事的只有委托者自己可以,代理者只是辅助作用而绝对不能(通常也没有能力)越俎代庖做委托者的事情,否则可能被代理的就是它自己了而不是它代理别人了。
在程序设计中,代理模式被较多用途:
1.懒加载:某类实例化成本较高,为提高效率通常先快速返回一个代理对象,后续通过异步或在真正有需要的时候进行真正实例化。
2.权限检查:对某对象的访问需要满足一定的权限要求,可以通过代理者去检查权限,满足权限要求则交给对象处理,否则直接返回错误不再传递给对象。
3.日志处理:对某对象的方法进行日志记录等操作,可以通过代理者来做,通过扩展不同的代理者完成许多辅助工作,实际工作本身依然由委托者自己来做。
可以把代理者看作是对象访问的经纪人,一个对象可以有一个或多个经纪人,不同的经纪人拦截对象的访问进而可以进行不同的处理工作。
场景:周先生是一个大牌电影演员,很会拍电影,很多导演都想请他去拍电影,如果每个导演都打打电话问他可能会占用他很多时间,另外他的联系方式也不容易搞到,怎么办?
给周先生整个经纪人吧,他对周先生的日程安排、拍电影能力等全部清楚,而且他不是什么大牌,很多人都可以轻易找到他进而了解到周先生是否有空拍电影,甚至经纪人还会做些记录,比如哪些导演来找过他,找他有什么事等等,总之,除了拍电影本身他在别人看来和周先生就像一个人。
分析:经纪人和周先生在外界看来像同一个人,那么他们必需实现同一个接口,经纪人包揽周先生的日程安排,在真正拍电影的时候交由周先生去做,那么经济人势必要关联到周先生,很显然经纪人是一个轻量级的对象,可以很快响应外界的请求,甚至周先生一直不出面都不会影响把程序搞死,顶多是告诉请求者周先生很忙。
设计:
示例代码:
interface MovieActor { void actMovie(); } class MrZhou implements MovieActor { @Override public void actMovie() { System.out.println("周先生眼电影 ..."); } } class ProxyActor implements MovieActor { private MovieActor movieActor; public ProxyActor(MovieActor movieActor) { this.movieActor = movieActor; } @Override public void actMovie() { System.out.println("经纪人先处理 ..."); movieActor.actMovie();// 交给委托者来实际完成。 } } public class Test { public static void main(String[] args) { MovieActor movieActor = new ProxyActor(new MrZhou()); movieActor.actMovie(); } }
以上是代理模式的实现,下面是使用JDK动态代理实现:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface MovieActor { void actMovie(); } class MrZhou implements MovieActor { @Override public void actMovie() { System.out.println("周先生眼电影 ..."); } } class ProxyActor implements InvocationHandler { private MrZhou mrZhou = new MrZhou(); @Override // 参数里的 proxy 其实是 Proxy.newProxyInstance 产生的匿名代理对象,对此对象的使用容易引发循环调用进而导致栈内存溢出 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); System.out.println("看看找电影演员有什么事情:" + name); if (name.equals("actMovie")) { mrZhou.actMovie(); } return null;//如果执行的方法有返回值,可以在这里返回 } } public class Test { public static void main(String[] args) { MovieActor movieActor = (MovieActor) Proxy.newProxyInstance( MrZhou.class.getClassLoader(), MrZhou.class.getInterfaces(), new ProxyActor()); movieActor.actMovie(); } }