本文是自己关于代理模式的一篇学习笔记,参考于 Android 源码设计模式解析与实战
1. 定义
当我们无法或不想直接访问某个对象或访问某个对象存在困难的时候,我们可以通过委托代理一个对象来间接访问,所以代理模式也称为委托模式。
1.1 代理模式的UML类图
- Subject: 抽象主题类, 用于声明真实主题与代理主题的共同接口方法,可以是一个抽象类也可以是一个接口。
- RealSubject: 真实主题类,也称为被委托类或被代理类, 用于定义代理所表示的真实对象。
- ProxySubject: 代理主题类, 也称为委托类, 该类持用真实主题类的引用,在其所实现的接口方法中调用真实主题类的接口方法,从而起到中间代理的作用。
- Client: 客户端类,即使用代理类的对象类。
1.1.1 代理模式的代码结构
Subject: 抽象主题类
/**
* @author jere
*
* 抽象主题类
*/
public abstract class Subject {
/**
* 一个普通的抽象方法
*/
public abstract void visit();
}
RealSubject: 真实主题类
/**
* @author jere
*
* 实现抽象主题的真实主题类
*/
public class RealSubject extends Subject {
private static final String TAG = "RealSubject";
@Override
public void visit() {
Log.i(TAG, "visit: ");
}
}
ProxySubject: 代理主题类
/**
* @author jere
*
* 实现抽象主题类的代理类
*/
public class ProxySubject extends Subject {
private static final String TAG = "ProxySubject";
//持有真实主题的引用
private RealSubject mRealSubject;
public ProxySubject(RealSubject realSubject) {
this.mRealSubject = realSubject;
}
@Override
public void visit() {
Log.i(TAG, "visit: ");
//调用真实主题类中的 visit() 方法
mRealSubject.visit();
}
}
Client: 客户端类
public class ProxyPatternTestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//构造一个真实主题实例
RealSubject realSubject = new RealSubject();
//构造一个代理主题实例,并且持有刚刚构造的真实主题实例
ProxySubject proxySubject = new ProxySubject(realSubject);
//调用代理主题实例的 visit() 方法
proxySubject.visit();
}
}
2. 代理模式的简单实现
在我们的生活中就存在很多的代理模式,比如绝大部分人都经历过的租房子,由于我们手上没有房源,很难租到心仪的房子,所以通常我们都是委托房产中介帮忙找房子,找到合适的房子后,我们支付中介费给房产中介。也有的人很忙,或者很懒,全权交给中介去帮我们干这些事。
简洁化一下流程,分成三个步骤:找房子 -> 联系房东 -> 签订合同
套入上述的代理模式结构中,就是:
- Subject:抽象主题 -> 租房子的步骤 -> IRentHouse.java
- RealSubject: 被代理类 -> 租客 -> Renter.java
- ProxySubject:代理类 -> 房产中介 -> HouseAgent.java
- Client: 客户端 -> 租房子事件 -> RentHouseTestActivity.java
2.1 具体代码
Subject:抽象主题 -> 租房子的步骤 -> IRentHouse.java
/**
* @author jere
* <p>
* Subject: 租房接口
*/
public interface IRentHouse {
/**
* 找房子
*/
void findHouse();
/**
* 联系房东
*/
void contactLandlord();
/**
* 签订合同
*/
void signContract();
}
RealSubject: 被代理类 -> 租客 -> Renter.java
/**
* @author jere
* <p>
* RealSubject: 租客
*/
public class Renter implements IRentHouse {
private static final String TAG = "Renter";
@Override
public void findHouse() {
Log.i(TAG, "findHouse: ");
}
@Override
public void contactLandlord() {
Log.i(TAG, "contactLandlord: ");
}
@Override
public void signContract() {
Log.i(TAG, "signContract: ");
}
}
ProxySubject:代理类 -> 房产中介 -> HouseAgent.java
/**
* @author jere
* <p>
* ProxySubject: 房产中介
*/
public class HouseAgent implements IRentHouse {
/**
* 被代理对象 -> 租客
*/
private IRentHouse mRenter;
public HouseAgent(IRentHouse renter) {
this.mRenter = renter;
}
@Override
public void findHouse() {
mRenter.findHouse();
}
@Override
public void contactLandlord() {
mRenter.contactLandlord();
}
@Override
public void signContract() {
mRenter.signContract();
}
}
Client: 客户端 -> 租房子事件 -> RentHouseTestActivity.java
/**
* @author jere
*
* Client :租房子
*/
public class RentHouseTestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//租客 -》明明
Renter mingMing = new Renter();
//明明找了房产中介 -》小李,委托他帮忙租一个房子
HouseAgent xiaoLi = new HouseAgent(mingMing);
//小李开始找房子
xiaoLi.findHouse();
//小李找到房子后联系房东
xiaoLi.contactLandlord();
//小李找到房子后替明明与房东签订合同
xiaoLi.signContract();
}
}
2.2 动态代理
上述的例子是静态代理实现方式,接着我们用动态代理来实现一下。
创建动态代理类:
/**
* @author jere
* <p>
* 动态代理类
*/
public class DynamicProxy implements InvocationHandler {
//被代理类
private Object object;
public DynamicProxy(Object o) {
this.object = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用被代理类对象的方法
return method.invoke(object, args);
}
}
然后我们就可以在我们的 Client 客户端,利用动态代理来动态创建一个代理类 -》 房产中介-小李,如下:
/**
* @author jere
*
* Client :租房子
*/
public class RentHouseTestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//被代理类:租客 -》明明
Renter mingMing = new Renter();
//构造一个动态代理
DynamicProxy dynamicProxy = new DynamicProxy(mingMing);
//获取被代理类 明明 的 classLoader
ClassLoader classLoader = mingMing.getClass().getClassLoader();
//动态构造一个代理类 房产中介 小李
IRentHouse xiaoLi = (IRentHouse) Proxy.newProxyInstance(classLoader, new Class[] {IRentHouse.class}, dynamicProxy);
//小李开始找房子
xiaoLi.findHouse();
//小李找到房子后联系房东
xiaoLi.contactLandlord();
//小李找到房子后替明明与房东签订合同
xiaoLi.signContract();
}
}
再次说明:本文参考于 Android 源码设计模式解析与实战