一 定义
代理模式也成为委托模式,是结构型模式中非常重要的模式。代理在我们的生活中常见,比如,你要租房子,找个中介帮你租,就是一种代理模式。你辞职了,老板必给你发工资,那么你得请个律师帮你打官司,也是一种代理。总之生活中,代理模式处处可见。
定义:为其他对象提供一种代理以控制对这个对象的访问。
二 模式结构
角色介绍:
- Subject:抽象主题类
该类的主要职责是声明真实主题与代理的共同接口方法,该类既可以是一个抽象类也可以是一个接口。 - RealSubject:真实主题类
该类也称为被委托类或被代理类,该类定义了代理所表示的真实对象,由其执行具体的业务逻辑方法,而客户类则通过代理类间接地调用真实主题类中定义的方法。 - ProxySubject:代理类
该类也称为委托类或代理类,该类持有一个对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行,以此起到代理的作用。 - Client:客户类
即使用代理类的类型。
三 实例
我们以生活中的租房子为例,我们知道,我们租房子可以直接找房东租,但是那样要浪费好多时间,我们我们可以找中介,找一个中间代理,委托代理全权完成租房过程。
- 抽象主题类
这里是一个接口,在接口里声明了真实主题类和代理类共同的方法。
/**
* 抽象主题类,租房子
*/
public interface IRent {
// 查找房源
void findHouse();
// 协商租金
void consult();
// 签订合同
void contract();
// 完成租房
void finish();
}
- 真实主题类
该类实现抽象主题类,并实现具体的逻辑方法。
public class XiaoMing implements IRent{
@Override
public void findHouse() {
System.out.println("查看房子");
}
@Override
public void consult() {
System.out.println("协商房租");
}
@Override
public void contract() {
System.out.println("签订租房合同");
}
@Override
public void finish() {
System.out.println("完成租房");
}
}
- 代理类
代理类也实现了抽象主题类,但是在该类里,会持有一个被代理者的引用,租房中介执行的方法,其实就是调用被代理者(小明)中的方法。
public class RentAgency implements IRent{
private IRent mIRent;
public RentAgency(IRent rent){
this.mIRent=rent;
}
@Override
public void findHouse() {
mIRent.findHouse();
}
@Override
public void contract() {
mIRent.contract();
}
@Override
public void consult() {
mIRent.consult();
}
@Override
public void finish() {
mIRent.finish();
}
}
- 测试代码
// 构造一个租房者小明
IRent XiaoMing=new XiaoMing();
// 构造一个租房代理,将小明作为构造参数传递进去
IRent agency=new RentAgency(XiaoMing);
// 中介帮忙查找房源
agency.findHouse();
// 中介帮忙协商房租
agency.consult();
// 中介帮忙,签订租房合同
agency.contract();
// 完成租房
agency.finish();
运行结果比较简单,在这就不贴出来了。
其实代理模式比较简单,就是一种委托机制,真实对象将方法的执行委托给代理对象处理。
四 静态代理和动态代理
其实代理模式大致可以分为两大部分,一是静态代理,二是动态代理。
- 静态代理,就如上面的示例那样,代理者的代码由程序员自己或者通过一些自动化工具生成固定的代码再对其进行编译。
- 动态代理,是通过反射机制动态地生成代理者对象,我们不需要手动创建代理类,Java给我们提供了一个便捷的动态代理接口InvocationHandler,实现该接口并重写其调用方法invoke。真正的代理对象由JDK在运行时为我们动态创建。
下面用动态代理的方式实现。
- 构建动态代理类
首先声明一个Object的引用,该引用将指向被代理类,而调用被代理类的具体方法则在invoke方法中执行。
public class DynamicRentProxy implements InvocationHandler {
private Object mObject;
public DynamicRentProxy(Object object){
this.mObject=object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用被代理类对象的方法
Object result=method.invoke(mObject, args);
return result;
}
}
- 测试代码
// 构造一个租房者小明
IRent XiaoMing=new XiaoMing();
// 构造一个动态代理
DynamicRentProxy proxy=new DynamicRentProxy(XiaoMing);
// 获取被代理类的ClassLoader
ClassLoader loader=XiaoMing.getClass().getClassLoader();
// 动态构造一个租房中介
IRent renter= (IRent) Proxy.newProxyInstance(loader,new Class[]{IRent.class},proxy);
// 中介帮忙查找房源
renter.findHouse();
// 中介帮忙协商房租
renter.consult();
// 中介帮忙,签订租房合同
renter.contract();
// 完成租房
renter.finish();
运行结果是一致的,再次不再贴出。
五 使用场景
代理模式的本质是控制对象的访问,当无法或者不想直接访问某个对象或者访问某个对象存在困难时,我们可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象和代理对象需要实现相同的接口。