代理模式也称为委托模式,其实代理在我们生活中也并不少见,最常见的莫过于代理上网了,连上代理服务器地址,就可以轻松浏览全世界的网站了,代理模式为其他对象提供了一种代理以控制对这个对象的访问。
代理模式的使用情景:
- 当无法或者不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口;
1.代理模式
UML 类图:
- Subject 表示抽象主题类,声明真实主题和代理的共同接口方法;
- RealSubject 表示真实主题类 (被代理类),定义了代理所表示的真实对象,由其执行具体的业务逻辑,客户类则通过代理类间接地调用真实主题定义的方法;
- ProxySubject 表示代理类,该类持有一个对真实主题类的引用,在其所实现的方法中调用主题类中的相应的接口方法执行,以此起到代理的作用;
- Client 表示客户类。
1.代码实现
代理模式的通用模式代码:
1、抽象主题类:
public interface Subject {
void visit();
}
2、实现抽象主题类的真实主题类(被代理类):
public class RealSubject implements Subject {
@Override
public void visit() {
System.out.println("visit");
}
}
3、代理类
public class ProxySubject implements Subject {
private RealSubject subject;
public ProxySubject(RealSubject subject) {
this.subject = subject;
}
// 织入方法执行之前的逻辑
public void beforeVisit() {
System.out.println("before visit");
}
@Override
public void visit() {
beforeVisit();
subject.visit();
afterVisit();
}
// 织入方法执行之后的逻辑
public void afterVisit() {
System.out.println("after visit");
}
}
测试代码:
@Test
public void test() throws Exception {
// 通过真实主题对象构造一个代理对象
ProxySubject proxy = new ProxySubject(new RealSubject());
// 调用代理的相关方法
proxy.visit();
}
输出结果:
before visit
visit
after visit
2.静态代理和动态代理
代理模式可以被大致分为静态代理和动态代理,静态代理代码编写再进行编译,也就是说代码运行前代理类的 class 编译文件就已存在,而动态代理则相反,动态代理通过反射机制动态地生成代理者的对象,也就是说在编码阶段并不知道代理谁,代理谁将会在执行阶段决定。
Java 给我们提供了一个便捷的动态代理接口 InvocationHandler,实现该接口需要重写其调用方法 invoke(),通过invoke()方法来调用具体的被代理方法,也就是真实的方法:
public class DynamicProxy implements InvocationHandler {
private Object obj; // 被代理的类引用
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
// 调用被代理类对象的方法
Object result = method.invoke(obj, objects);
return result;
}
}
我们声明了一个 Object 的引用,该引用将指向被代理类,也就是说原来由代理类所做的工作现在由 InvocationHandler 处理。下面我们修改一下测试代码的逻辑:
@Test
public void test() throws Exception {
// 创建真实主题对象
RealSubject subject = new RealSubject();
// 构造一个动态代理
DynamicProxy dynamicProxy = new DynamicProxy();
// 获取被代理类subject的ClassLoader
ClassLoader loader = subject.getClass().getClassLoader();
// 动态构造一个代理者
RealSubject proxy = (RealSubject)Proxy.newProxyInstance(loader,
new Class[] {RealSubject.class}, dynamicProxy);
// 调用代理的相关方法
proxy.visit();
}
动态代理通过一个代理类来代理N多个被代理类,其实质上对代理者与被代理者进行解耦,使两者没有直接的耦合关系,相对而言静态代理则只是为给定接口的实现类做代理,如果接口不同那么就需要重新定义不同代理类,较为复杂,但是静态代理更符合面向对象原则,开发时需要具体情况具体对待选择了。