大家好,我是极客涛,今天我们聊一聊java中的代理模式,话不多说,还是老思路,什么是代理模式,为什么要有代理模式,如何实现代理模式
在说java中的代理模式之前,我们可以先想一想生活的例子,这里也是一个加深自己对程序设计理解的一种学习方式,程序本质上就是对生活的抽象和实现。
生活中的代理模式太多了:
这里如果我们进行抽象的话,对于租房来说,我本身只有判断房子适不适合我的能力,但是我没有(不想)对房源进行检索的能力,这时候中介其实就是代理了我对房源进行检索,但最终房子适不适合还是我自己决定;对点外卖来说,我不想自己去店里拿,所以外卖小哥代理了我帮把饭送到我手上,我自己用吃的能力。
也就是说,代理模式的核心就是对被代理对象的能力拓展。
我们拿我吃饭的场景举例说明
/**
* 人
*/
public interface Person {
/**
* 吃
*/
void eat();
}
/**
* 我
*/
public class GeekTao implements Person {
@Override
public void eat() {
System.out.println("我自己吃饭");
}
}
/**
* 外卖员
*/
public class Taker implements Person {
private final Person me;
public Taker() {
me = new GeekTao();
}
@Override
public void eat() {
// 送外卖
this.send();
// 吃饭
me.eat();
}
private void send() {
System.out.println("外卖员把外卖送到家");
}
}
测试方法
public class ProxyTest {
public static void main(String[] args) {
Person taker = new Taker();
taker.eat();
}
}
运行结果
外卖员把外卖送到家
我自己吃饭
真好,现在可以不用自己去拿外卖,外卖小哥就把外卖送到了;还有个问题,吃完我又口渴了,如果我还想喝,抽象一个drink方法,外卖小哥是不是还得实现一个drink方法?下边做个简单示例。
/**
* 外卖员
*/
public class Taker implements Person {
private final Person me;
public Taker() {
me = new GeekTao();
}
@Override
public void eat() {
// 送外卖
this.send();
// 吃饭
me.eat();
}
private void send() {
System.out.println("外卖员把外卖送到家");
}
@Override
public void drink() {
// 送外卖
this.send();
// 喝水
me.drink();
}
}
以上实现其实就是静态代理,核心在于“静态”,对于我来说外卖小哥要实现一次,除了我还有很多人也需要点外卖,那外卖小哥每个都要适配一次;每次我自己有了新的需求(方法),外卖小哥也要跟着实现,但其实对于他来说实现方法都一样(都是送外卖),所以这也是静态代理的缺点,非常不灵活。
还是拿我吃饭的场景举例子,上边说到外卖小哥不只是给我送外卖,那如何实现一个小哥可以给不同的人送外卖呢?
其它类和上边例子一样,只贴了TakerCommon。
/**
* 通用外卖员
*/
public class TakerCommon implements InvocationHandler {
private Object proxyTarget;
public Object sendWho(Object target) {
this.proxyTarget = target;
return Proxy.newProxyInstance(proxyTarget.getClass().getClassLoader(), proxyTarget.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("外卖员送外卖给 " + proxyTarget.getClass().getSimpleName());
return method.invoke(proxyTarget, args);
}
}
测试方法
public class ProxyTest {
public static void main(String[] args) {
TakerCommon takerCommon = new TakerCommon();
Person me = (Person) takerCommon.sendWho(new GeekTao());
me.eat();
System.out.println("========================");
Person xiaoming = (Person) takerCommon.sendWho(new XiaoMing());
xiaoming.eat();
}
}
测试结果
外卖员送外卖给 GeekTao
我自己吃饭
========================
外卖员送外卖给 XiaoMing
小明吃饭
这时候我又想喝,那直接调用drink方法就行了,因为对于外卖小哥来说都是一样的。
测试方法
public class ProxyTest {
public static void main(String[] args) {
TakerCommon takerCommon = new TakerCommon();
Person me = (Person) takerCommon.sendWho(new GeekTao());
me.eat();
me.drink();
System.out.println("========================");
Person xiaoming = (Person) takerCommon.sendWho(new XiaoMing());
xiaoming.eat();
xiaoming.drink();
}
}
测试结果
外卖员送外卖给 GeekTao
我自己吃饭
外卖员送外卖给 GeekTao
我自己喝
========================
外卖员送外卖给 XiaoMing
小明吃饭
外卖员送外卖给 XiaoMing
小明在喝
代理模式的核心就是对被代理对象的能力拓展
静态代理适合简单业务,不经常变动,因为实现逻辑简单,开发成本低
动态代理适合变动可能性较大的业务。