代理模式定义:对其他对象提供一种代理以控制对这个对象的访问。
- 代理模式的主要作用
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 - 代理模式的思想
为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
现实生活中也有很类似的情形。比如打官司需要请律师,买房子需要找中介等等。
以买车为例,如果我们要买一辆轿车必须通过汽车4S店,汽车4s店就是充当代理角色,其目的就是控制买车客户的买车行为,必须通过汽车4S店才能从汽车厂商买一辆车。
静态代理
- 首先新建一个买车的接口
public interface IBuyCar {
//买车
void buyCar();
}
- 声明一个要买车的客户,实现买车接口
public class Customer implements IBuyCar {
private int cash;//购车款
public int getCash() {
return cash;
}
public void setCash(int cash) {
this.cash = cash;
}
@Override
public void buyCar() {
Log.e("buyCar", "买一辆车花费了-->" + cash + "元");
}
}
- 声明一个买车代理汽车4S店,同样也实现买车接口,必须接受客户下单
public class BuyCarProxy implements IBuyCar{
private Customer customer;//接收买车客户
public BuyCarProxy(Customer customer){
this.customer=customer;//接收买车客户
}
@Override
public void buyCar() {//实现为客户买车
customer.buyCar();
}
}
- 创建一个客户端,模拟一次买车
Customer customer=new Customer();
customer.setCash(120000);
BuyCarProxy buyCarProxy=new BuyCarProxy(customer);
buyCarProxy.buyCar();
动态代理
以上讲的都是代理模式的静态实现,所谓静态代理就是自己要为要代理的类写一个代理类,或者用工具为其生成的代理类,总之,就是程序运行前就已经存在的编译好的代理类,这样有时候会觉得非常麻烦,也导致非常的不灵活,相比静态代理,动态代理具有更强的灵活性,因为它不用在我们设计实现的时候就指定某一个代理类来代理哪一个被代理对象,我们可以把这种指定延迟到程序运行时由JVM来实现。
- 首先我们要声明一个动态代理类,实现InvocationHandler接口
public class DynamicProxy implements InvocationHandler {
// 被代理类的实例
Object obj;
// 将被代理者的实例传进动态代理类的构造函数中
public DynamicProxy(Object obj) {
this.obj = obj;
}
/**
* 覆盖InvocationHandler接口中的invoke()方法
* 更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构
* 的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到
* 控制被代理对象的行为,下面的before、after就是我们可以进行特殊
* 代码切入的扩展点了。
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*
* before :doSomething();
*/
Object result = method.invoke(this.obj, args);
/*
* after : doSomething();
*/
return result;
}
}
- 具体实现
//我们要代理的真实对象
Customer customer = new Customer();
//我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new DynamicProxy(customer);
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的
* ClassLoader对象来加载我们的代理对象
* 第二个参数customer.getClass().getInterfaces(),我们这里为代理对象提供的接口是
* 真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
IBuyCar buyCar = (IBuyCar) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
customer.getClass().getInterfaces(), handler);
buyCar.buyCar();
- 动态代理好处
- 减少编程的工作量:假如需要实现多种代理处理逻辑,只要写多个代理处理器就可以了,无需每种方式都写一个代理类。
- 系统扩展性和维护性增强,程序修改起来也方便多了(一般只要改代理处理器类就行了)。