什么是代理模式
在公司上班,每月都要缴纳社保,你从来没有自己去社保中心缴纳过,都是由公司人力部门代你缴纳,人力小姐姐就是你的代理人,帮你做了这件事情。
火车票由铁路局印售,全国各地都有火车票代售点,你去最近的代售点就能买到你想要的车票,不用跑去铁路局,代售点就是铁路局的代理人,负责代理售卖火车票。
我具备做一件事情的能力,但是我又不想亲自做,就招个代理帮我做事情,这就是代理模式。
代理模式有两个角色:代理者、被代理者。代理者帮被代理者做事情,被代理者是幕后的老板,代理者只是个跑腿的。
代理模式应用到编程中,又被分为两个概念:静态代理、动态代理。两者区别:
- 静态代理:系统运行前,代理类就存在
- 动态代理:系统运行前,代理类不存在,运行后动态生成代理类
模式设计与实现
因为代理模式只涉及两个核心角色:代理者、被代理者。
所以模式设计相对简单,不管怎么设计,只要能完成代理任务,就都可以称之为代理模式。
具体到编程语言的实现,就各有各的方法,这里以Java
语言为例,讲述代理模式的实现方法。
静态代理
原则是代理类事先就存在,那就只能自己手写代理类了。
因此,静态代理的Java
代码实现,大概是这样的:
public interface Subject {
void request();
}
// 被代理类
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("do something");
}
}
// 代理类
public class RealSubjectProxy implements Subject {
private RealSubject realSubject = new RealSubject();
@Override
public void request() {
System.out.println("proxy do something");
realSubject.request();
System.out.println("proxy do something");
}
}
前面说,代理者是帮被代理者做事情的,但是,看代码逻辑,虽然经过代理类,可最后感觉还是要劳烦被代理者自己把事情做了。
不知道读者有没有类似的感觉,反正我以前有过。后来想明白了,总结出代理模式的另一个特点:
代理者帮助被代理者做事情,可以添加一些辅助任务,但是核心任务必须通过被代理者去完成。
什么意思呢?就是说:
- 代售点可以帮铁路局收钱记账,但是卖票的核心任务还是由铁路局控制的
- 人力小姐姐可以帮你计算社保并代缴,但是核心的社保信息还得是你的
动态代理
JDK
本身就提供有动态代理的机制,通过反射等手段,在系统运行的时候,动态生成代理类,还是比较方便的。
大概的代码如下:
public interface Subject {
void request();
}
// 被代理类
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("do something");
}
}
// 这个类的主要内容是"代理任务的执行逻辑",它不是代理类
public class ProxyLogic implements InvocationHandler {
private Object realSubject;// 真实主题
public RealSubjectDynamicProxy(Object realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy do something");
Object invoke = method.invoke(realSubject, args);
System.out.println("proxy do something");
return invoke;
}
}
// 测试方法,展示如果生成代理类
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
// 代理类:动态生成的
Subject proxy = (Subject) Proxy.newProxyInstance(
RealSubject.class.getClassLoader(),
new Class[]{Subject.class},
new ProxyLogic(realSubject)
);
}
动态代理不像静态代理那样,要把整个代理类都写一遍,但是核心的代理逻辑还是要写的。
为什么这么写,不是本文的重点,有兴趣的可以去了解java.lang.reflect.Proxy
的实现逻辑。
总结
- 如果单纯只说设计模式,就只有“代理模式”这一说,具体到编程语言的实现,才有静态代理、动态代理这两种区分
- 静态代理写法简单,编码灵活度高,例如代理类方法名、被代理类哪些方法需要代理,都是可以自由选择的
- 动态代理写法稍微复杂,编码灵活度不高,但是编码规范度较高。如果被代理类方法较多,代理逻辑又是相同的,就适合使用动态代理,可以大幅度减少代码量