常见设计模式——代理模式
Intent
控制对其它对象的访问。
Class Diagram
抽象角色:声明真实对象和代理对象的共同接口,这样在任何使用真实对象的地方都可以使用代理对象。
代理角色:代理对象内部含有真实对象的引用,从而可以在任何时候操作真实对象。代理对象和真实对象具有相同的接口,这样就可以在任何时候替代真实对象。代理对象通常在执行真实对象的操作前后,附加某些其他的操作,相当于对真实对象进行封装。
真实角色:即为代理对象所代理的真实对象,是我们最终要引用的对象。
Implementation
// 抽象角色
interface Subject{
public void doSomething();
}
// 目标角色
class RealSubject implements Subject{
public void doSomething() {
System.out.println("call doSomething()");
}
}
// 代理角色
class SubjectProxy implements Subject{
// 代理持有目标对象的引用
Subject subimpl = new RealSubject();
public void doSomething() {
System.out.println("before"); //调用目标对象之前可以做相关操作
subimpl.doSomething();
System.out.println("after");//调用目标对象之后可以做相关操作
}
}
public class Test {
public static void main(String[] args) throws Exception {
Subject sub = new SubjectProxy();
sub.doSomething();
}
}
存在的问题:
1. 如果 RealSubject 将来需要实现一个新的接口,就需要在代理类里再写该接口的实现方法,导致代理类的代码变得臃肿
2. 当需要改变抽象角色接口时,无疑真实角色和代理角色也需要改变。
JDK动态代理
package com.eastern.msap.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Subject {
public void doSomething();
}
class RealSubject implements Subject {
public void doSomething() {
System.out.println("call doSomething()");
}
}
class ProxyHandler implements InvocationHandler {
private Object target;
public ProxyHandler(Object target) {
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),// 绑定该类实现的所有接口,取得代理类
this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
System.out.println("在调用具体函数方法前,执行功能处理");
result = method.invoke(target, args);
System.out.println("在调用具体函数方法后,执行功能处理");
return result;
}
}
public class Test {
public static void main(String args[]) {
ProxyHandler proxyHandler = new ProxyHandler(new RealSubject());
Subject sub = (Subject) proxyHandler.getProxyInstance();
sub.doSomething();
}
}
在调用具体函数方法前,执行功能处理
call doSomething()
在调用具体函数方法后,执行功能处理
对于问题一,因为JDK动态代理是根据目标对象实现的所有接口生成代理类对象的,所以如果目标对象需要实现新接口时,生成代理类的代码不用做更改。
对于问题二,当接口改变的时候,虽然【被代理类】需要改变,生成代理类的代码也不用更改。
这个调用虽然足够灵活,可以动态生成一个具体的代理类,而不用自己显式的创建一个实现具体接口的代理类。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步