一. 前言
1. 定义
Proxy Pattern:给目标对象提供一个代理对象,并由代理对象控制对目标对象的访问。
二. 静态代理
1. 概况
背景:有一个人想找代购,购买口红。
2. 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
public class StaticProxy {
public interface Person { void buy(); }
public static class Demand implements Person {
String thing;
public Demand(String thing) { this.thing = thing; }
@Override public void buy() { System.out.println("被代理者-需求者:我想买"+thing); } }
public static class Purchase implements Person { Person person;
public Purchase(Person person) { this.person = person; }
@Override public void buy() { System.out.println("代理者-代购:你想买什么东西");
person.buy(); } }
public static void main(String[] args) { Demand demand = new Demand("口红");
Purchase purchase = new Purchase(demand); purchase.buy(); } }
|
1 2 3
| 代理者-代购:你想买什么东西 被代理者-需求者:我想买口红
|
三. 动态代理
1. 概况
背景:有一个人张三想找代购,购买口红。又有一个人李四想找代购,购买面膜。
2. 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
public class DynamicProxy {
public interface Person { void buy(); }
public static class Demand implements Person { String name; String thing;
public Demand(String name, String thing) { this.name = name; this.thing = thing; }
@Override public void buy() { System.out.println("被代理者-"+name+":我想买"+thing); } }
public static class Purchase implements InvocationHandler { Object object;
public Object newPurchase(Object object) { this.object = object;
return Proxy.newProxyInstance( object.getClass().getClassLoader(), object.getClass().getInterfaces(), this ); }
@Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { System.out.println("代理者-代购:你想买什么东西");
return method.invoke(object, objects); } }
public static void main(String[] args) { Demand demand1 = new Demand("张三", "口红"); Demand demand2 = new Demand("李四", "面膜");
Purchase purchase = new Purchase();
Person person1 = (Person) purchase.newPurchase(demand1); Person person2 = (Person) purchase.newPurchase(demand2);
person1.buy(); person2.buy(); } }
|
1 2 3 4 5
| 代理者-代购:你想买什么东西 被代理者-张三:我想买口红 代理者-代购:你想买什么东西 被代理者-李四:我想买面膜
|
3. 关于代码中一些接口或方法的理解
① InvocationHandler接口
InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。
每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用,看如下invoke方法:
1 2 3 4 5 6 7 8
|
public interface InvocationHandler { Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
|
② Proxy类
1 2 3 4 5 6
|
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler i) throws IllegalArgumentException
|
③ 参考
Java动态代理InvocationHandler和Proxy学习笔记
四. 系统中的例子
Android的源码中多个地方都用到代理模式,比如ActivityManagerProxy
这个代理类。
五. 静态代理和动态代理的区别
1. 静态代理的缺点
2. 动态代理的优点
- 可以通过一个代理类完成全部的代理功能,接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(
InvocationHandler.invoke
)。当接口方法数量较多时,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
- 动态代理的应用使我们的类职责更加单一,复用性更强。
3. 动态代理的缺点
不能对类进行代理,只能对接口进行代理,如果我们的类没有实现任何接口,那么就不能使用这种方式进行动态代理(因为$Proxy()这个类集成了Proxy,Java的集成不允许出现多个父类)。
六. 优缺点以及应用场景
1. 优点
- 代理作为调用者和真实主题的中间层,降低了模块间和系统的耦合性。
- 可以以一个小对象代理一个大对象,达到优化系统提高运行速度的目的。
- 代理对象能够控制调用者的访问权限,起到了保护真实主题的作用。
2. 缺点
- 由于在调用者和真实主题之间增加了代理对象,因此可能会造成请求的处理速度变慢。
- 实现代理模式需要额外的工作(有些代理模式的实现非常复杂),从而增加了系统实现的复杂度。
3. 应用场景
当一个对象不能或者不想直接访问另一个对象时,可以通过一个代理对象来间接访问。为保证客户端使用的透明性,委托对象和代理对象要实现同样的接口。
被访问的对象不想暴露全部内容时,可以通过代理去掉不想被访问的内容。
根据适用范围,代理模式可以分为以下几种:
- 远程代理:为一个对象在不同的地址空间提供局部代表,这样系统可以将Server部分的事项隐藏。
- 虚拟代理:如果要创建一个资源消耗较大的对象,可以先用一个代理对象表示,在真正需要的时候才真正创建。
- 保护代理:用代理对象控制对一个对象的访问,给不同的用户提供不同的访问权限。
- 智能引用:在引用原始对象的时候附加额外操作,并对指向原始对象的引用增加引用计数。
参考文章
代理模式(Proxy Pattern):静态代理 - 最易懂的设计模式解析
代理模式(Proxy Pattern):动态代理 - 最易懂的设计模式解析
Android的设计模式-代理模式