第十八章、代理模式
代理模式也称委托模式,是结构型设计模式之一。是应用广泛的模式之一。
1.定义
为其他对象提供一种代理以控制对这个对象的访问。
2.使用场景
当无法或不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。
3.UML类图
(1)Subject:抽象主题类,声明真实主题与共同接口方法,该类可以是抽象类或接口。
(2)RealSubject:真实主题类(被委托类),尤其执行具体的业务逻辑方法。
(3)Proxy:代理类(委托类),该类持有一个对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行,以此起到代理作用。
4.简单实现
书中例子:以小民诉讼的流程举例。那么需要代理律师代理,诉讼简单流程:提交申请–>进行举证–>开始辩护–>诉讼完成。
诉讼接口类:
public interface ILawsuit {
/**
* 提交申请
*/
void submit();
/**
* 进行举证
*/
void burden();
/**
* 开始辩护
*/
void defend();
/**
* 诉讼完成
*/
void finish();
}
具体诉讼人小民:
public class XiaoMin implements ILawsuit{
@Override
public void submit() {
//小民申请仲裁
System.out.println("老板年底拖欠工资,特此申请仲裁!");
}
@Override
public void burden() {
//小民提交证据
System.out.println("这是合同书和过去一年的银行工资流水!");
}
@Override
public void defend() {
//铁证如山
System.out.println("证据确凿,不需要再说什么!");
}
@Override
public void finish() {
//结果
System.out.println("诉讼成功,判决老板即日起七天内结算工资!");
}
}
代理律师:
public class Lawyer implements ILawsuit{
private ILawsuit mLawsuit; //持有一个具体被代理者的引用
public Lawyer(ILawsuit lawsuit) {
this.mLawsuit = lawsuit;
}
@Override
public void submit() {
mLawsuit.submit();
}
@Override
public void burden() {
mLawsuit.burden();
}
@Override
public void defend() {
mLawsuit.defend();
}
@Override
public void finish() {
mLawsuit.finish();
}
}
开始仲裁:
public class Client {
public static void main(String[] args) {
//构造出诉讼人小民
ILawsuit xiaomin = new XiaoMin();
//构造一个代理律师,并将小民传递进去
ILawsuit lawyer = new Lawyer(xiaomin);
//律师提交申请
lawyer.submit();
//律师进行举证
lawyer.burden();
//律师代小民辩护
lawyer.defend();
//完成诉讼
lawyer.finish();
}
}
结果:
老板年底拖欠工资,特此申请仲裁!
这是合同书和过去一年的银行工资流水!
证据确凿,不需要再说什么!
诉讼成功,判决老板即日起七天内结算工资!
同样我们也可以代理其他人,只需要实现ILawsuit即可。上面的代理模式也叫静态代理,也就是在代码运行前代理类的class文件就已经存在。那么相反,当然也会有动态代理,下面用动态代理实现上述例子:
Java提供了一个便捷的动态代理接口InvocationHandler,我们来实现它:
public class DynamicPorxy implements InvocationHandler{
private Object obj; //被代理类的引用
public DynamicPorxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 调用被代理类对象的方法
Object result = method.invoke(obj, args);
return result;
}
}
这里我们通过invoke方法来调用具体的被代理方法。
修改后的Client类:
public class Client {
public static void main(String[] args) {
//构造出诉讼人小民
ILawsuit xiaomin = new XiaoMin();
//1.静态代理
//构造一个代理律师,并将小民传递进去
//ILawsuit lawyer = new Lawyer(xiaomin);
//--------------------------------------
//2.动态代理
//构造一个动态代理
DynamicPorxy proxy = new DynamicPorxy(xiaomin);
//获取被代理类小民的ClassLoader
ClassLoader loader = xiaomin.getClass().getClassLoader();
//动态构造一个代理者律师
ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader, new Class[]{ ILawsuit.class }, proxy);
//律师提交申请
lawyer.submit();
//律师进行举证
lawyer.burden();
//律师代小民辩护
lawyer.defend();
//完成诉讼
lawyer.finish();
}
}
结果不变,由此可以看出动态代理通过一个代理类来处理N多个被代理类,其实质是对代理者与被代理者解耦。相对而言静态代理则只能为给定接口下的实现类做代理,如果接口不同那么就需要重新定义不同的代理类,较为复杂,但是静态代理更符合面向对象原则。具体使用哪种方式,根据个人喜好。
5.Android源码中的代理模式实现
1.ActivityManagerProxy代理类
ActivityManager是Android中管理和维护Activity的相关信息的类,为了隔离它与ActivityManagerService,有效降低二者的耦合,在这中间使用了ActivityManagerProxy代理类,所有对ActivityManagerService的访问都转换成对代理类的访问,这样ActivityManager就与ActivityManagerService解耦了。
6.总结
1.优点
(1)对代理者与被代理者进行解耦。
(2)代理对象在客户端和目标对象之间起到一个中介的作用,这样可以起到对目标对象的保护。
2.缺点
基本没有缺点,真要说缺点就是设计模式的通病:对类的增加。