定义
为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用。(结构型)
如果不知道代理模式,可能大家对代理服务器都不叫熟悉。代替服务器代替请求者去发一起对另一个服务器的请求,他相当于请求的中间人。为什么要通过这个代理呢,那是因为客户端直接去访问服务器会被拒绝(防火墙屏蔽),而代理服务器则可以直接访问服务器。这里有两种应用场景,一种是国内的翻墙了(静态代理),另一种是hacker想掩盖自己的ip时,往往会通过多层代理服务器进行访问/或者不停的切换代理(动态代理,《who am i》电影里面男主就是通过代理去和另外一个haacker通信,而且所用的代理一直在变防止被追踪到)
模板
抽象角色(Subject)
通过接口或抽象类声明真实角色实现的业务方法。
代理角色(RealSubject)
实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作
真实角色(Proxy)
实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用
实例
a) 静态代理
Main中去调用ProxyPrinter中的print方法而不需要关心被代理类(Printer),由于代码比较简单,这里就不具体展开。
b) 动态代理
这里列举了一个可以将任何方法的执行放在指定线程(提前创建好的UI线程和后台线程)的动态代理实现,具体如下:
假如一个有一个写文件的操作类如下:
public class FileWriter {
private void writeBytesToFile(String fileName, Byte[] bytes) {
// 将二进制文件写入到 文件中
}
}
做过前端开发的应该都知道写文件是一个耗时操作,不能在主线程中执行,那我们现在怎么办?
FileWriter fileWriter = new FileWriter();
FileWriter proxyWriter = ObjectThreadProxy.back(fileWriter, FileWriter.class);
proxyWriter.writeBytesToFile("TestFile.txt", xxxx);
上述代码通过前面讲的ObjectThreadProxy工具类就可以将被代理的对象转换成proxyWriter,接下来调用proxyWriter的任何方法都会执行在子线程中。这是如何做到的,具体看一下back方法及ThreadInvocationHandler就知道了:
// back 方法中创建代理类
ThreadInvocationHandler handler = new ThreadInvocationHandler(realObj, syncMode);
Object proxyObj = Proxy.newProxyInstance(class.getClassLoader(), new Class[]{class}, handler);
return proxyObj;
// ThreadInvocationHandler 中invoke方法关键代码如下:
public Object invoke(Object proxy, final Method method, final Object[] args) {
switch(mode) {
case BACK:
// 在子线程执行方法
method.invoke(readObject, args);
break;
case MAIN:
// 在主线程中执行
break;
}
优点
1.代理模式能将代理对象与真实对象被调用的目标对象分离,一定程度上降低了系统的耦合度,扩展性好。
2.保护目标对象。
3.增强目标对象。
缺点
- 创建多个类,增加代码阅读复杂性(所有设计模式通病)
- clone方法只是浅拷贝,除五种基础类型之外类型都只是简单的指向引用,不会重新创建成员变量,如需实现需要自定义clone方法。
- 通过clone方法不会调用类的构造函数,部分场景(在构造函数中做一些初始化操作的)需要做额外的处理
适用场景
1.保护目标对象
2.增强目标对象
与装饰模式的区别
对对象的作用
装饰者:动态的新增或组合对象的行为,在不改变接口的前提下,动态扩展对象的功能
代理模式:为其他对象提供一种代理以控制对这个对象的访问,在不改变接口的前提下,控制对象的访问
如何使用该对象
装饰者:通常将原始对象作为参数传递给Decorator的构造函数。
代理模式:代理类中创建一个真实对象的实例
注: 其实代理模式也可以作为参数传递,这里是网上很多地方的写法,自己并不赞同。
模式的核心
装饰者:强调的是增强自身,在被装饰之后你能够在被增强的类上使用增强后的功能。增强后你还是你,只不过能力更强了而已
代理模式:强调要让别人去做一些本身和你业务没有太多关系的职责(记录日志,设置缓存,远程代理负责网络通信的一些细节),代理模式是为了实现对对象的控制,因为被代理的对象往往难以直接获得或者其内部不想暴露出来
其它实例:
待补充