建造者模式定义:
由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
实现:
根据代理的创建时期,代理模式分为静态代理和动态代理。
- 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。
- 动态:在程序运行时,运用反射机制动态创建而成。
静态代理
静态代理服务于单个接口,我们来考虑实际工程中的一个例子,现在已经有业务代码实现一个增删功能,原有的业务代码由于仍有大量程序无法改变,现在新增需求,即以后每执行一个方法输出一个日志。
我们不改变原有代码而添加一个代理来实现:
//业务接口
interface DateService {
void add();
void del();
}
class DateServiceImplA implements DateService {
@Override
public void add() {
System.out.println("成功添加!");
}
@Override
public void del() {
System.out.println("成功删除!");
}
}
class DateServiceProxy implements DateService {
DateServiceImplA server = new DateServiceImplA();
@Override
public void add() {
server.add();
System.out.println("程序执行add方法,记录日志.");
}
@Override
public void del() {
server.del();
System.out.println("程序执行del方法,记录日志.");
}
}
//客户端
public class Test {
public static void main(String[] args) {
DateService service = new DateServiceProxy();
service.add();
service.del();
}
}
动态代理实现
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//业务接口
interface DateService {
void add();
void del();
}
class DateServiceImplA implements DateService {
@Override
public void add() {
System.out.println("成功添加!");
}
@Override
public void del() {
System.out.println("成功删除!");
}
}
class ProxyInvocationHandler implements InvocationHandler {
private DateService service;
public ProxyInvocationHandler(DateService service) {
this.service = service;
}
public Object getDateServiceProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), service.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
var result = method.invoke(service, args); // 让service调用方法,方法返回值
System.out.println(proxy.getClass().getName() + "代理类执行" + method.getName() + "方法,返回" + result + ",记录日志!");
return result;
}
}
//客户端
public class Test {
public static void main(String[] args) {
DateService serviceA = new DateServiceImplA();
DateService serviceProxy = (DateService) new ProxyInvocationHandler(serviceA).getDateServiceProxy();
serviceProxy.add();
serviceProxy.del();
}
}
/*
成功添加!
$Proxy0代理类执行add方法,返回null,记录日志!
成功删除!
$Proxy0代理类执行del方法,返回null,记录日志!
*/
代理模式通常有如下几种用途:
- 远程代理,这种方式通常是为了隐藏目标对象存在于不同地址空间的事实,方便客户端访问。例如,用户申请某些网盘空间时,会在用户的文件系统中建立一个虚拟的硬盘,用户访问虚拟硬盘时实际访问的是网盘空间。
- 虚拟代理,这种方式通常用于要创建的目标对象开销很大时。例如,下载一幅很大的图像需要很长时间,因某种计算比较复杂而短时间无法完成,这时可以先用小比例的虚拟代理替换真实的对象,消除用户对服务器慢的感觉。
- 保护代理,当对目标对象访问需要某种权限时,保护代理提供对目标对象的受控保护,例如,它可以拒绝服务权限不够的客户。
- 智能指引,主要用于调用目标对象时,代理附加一些额外的处理功能。例如,增加计算真实对象的引用次数的功能,这样当该对象没有被引用时,就可以自动释放它(C++智能指针);例如上面的房产中介代理就是一种智能指引代理,代理附加了一些额外的功能,例如带看房等。
代理模式的优点:
- 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
- 代理对象可以扩展目标对象的功能;
- 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性;
缺点:
- 静态代理模式会造成系统设计中类的数量增加,但动态代理可以解决这个问题;
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
- 增加了系统的复杂度;