代理模式介绍

代理模式(Proxy Pattern)也称为委托模式,是结构型设计模式的一种,代理模式在各类开发中运用的相当广泛,不论是j2ee,android还是ios,都能看到它的身影,所以说设计模式无处不在。

代理模式的定义:

为其他对象提供一种代理以控制这个对象的访问。通俗一点:找别人做你想做但是做不了的事情。

代理模式的UML类图,如图:

android proxy Settings怎么配置_AMS

角色介绍:

(1) 抽象主题(Subject):定义了真实主题(RealSubject)和代理  (Proxy)的公共接口,这样就在任何时候使用真实主题(RealSubject)的地方使用代理(Proxy)。
  (2) 代理(Proxy):保存一个引用使得代理可以直接访问真实主题,并提供一个与Subject的接口相同的接口,这样代理就可以代替真实主题。
  (3) 真实主题(RealSubject):定义Proxy所代表的真实主题。
  (4) 客户类(Client):即使用代理类的类型。

代理模式的简单实现

背景描述

在生活中代理模式也是经常存在,比如2011年老罗针对西门子冰箱门关不严,进行维权。假设找到了律师进行维权,那么这种方式就是代理模式,当然老罗可以自己打官司,也可以自己打官司,有相同的地方,也有不同的地方。

相同的地方在于:
1、 诉讼申请:都需要提交原告的资料,如姓名、年龄、事情缘由、想达到的目的。
2、 诉讼取证:都需要经过法院的取证调查,开庭争辩等过程。
3、 诉讼完成:最后拿到审判结果。

不同地方在于:
1、 节省时间:老罗省事了,让专业的人做专业的事,不需要自己再去了解法院那一套繁琐复杂的流程。
2、 成功性概率:把握更大了。

通过上面的例子,我们注意到代理模式有几个重点。
1、 被代理的角色(老罗)
2、 代理角色(律师)
3、 协议(不管是代理和被代理谁去做,都需要做的事情,抽象出来就是协议)

具体代码实现
定义诉讼协议接口ILawProtocol.java:
/**
 *诉讼协议接口:规定诉讼的一般流程
 */
public interface ILawProtocol {
    void submit();//提交申请
    void burden();//进行举证
    void defend();//开始辩护
    void finish();//诉讼完成
}
定义具体的诉讼人LaoLuo .java:
/*
 * 具体的诉讼人:继承诉讼接口
 */
public class LaoLuo implements ILawProtocol{

    @Override
    public void submit() {
        // TODO Auto-generated method stub
        System.out.println("申请:西门子冰箱质量缺陷,特此申请民事仲裁!");
    }

    @Override
    public void burden() {
        // TODO Auto-generated method stub
        System.out.println("证据:这是购买冰箱的发票,以及冰箱质量问题的视频!");
    }

    @Override
    public void defend() {
        // TODO Auto-generated method stub
        System.out.println("辩护:我们证据确凿,必须得到应该的赔偿!");
    }

    @Override
    public void finish() {
        // TODO Auto-generated method stub
        System.out.println("诉讼完成:判决西门子北京分公司在七日之内退还老罗购买冰箱的成本!");
    }
}
定义代理律师类Lawyer .java
/*
 * 代理律师类:继承诉讼接口
 */
public class Lawyer implements ILawProtocol{

    private ILawProtocol mILawSuit;//关联一个诉讼人
    public Lawyer(ILawProtocol mILawSuit) {
        super();
        this.mILawSuit = mILawSuit;
    }

    @Override
    public void submit() {
        // TODO Auto-generated method stub
        mILawSuit.submit();//提交申请
    }

    @Override
    public void burden() {
        // TODO Auto-generated method stub
        mILawSuit.burden();//进行举证
    }

    @Override
    public void defend() {
        // TODO Auto-generated method stub
        mILawSuit.defend();//开始辩护
    }

    @Override
    public void finish() {
        // TODO Auto-generated method stub
        mILawSuit.finish();//诉讼完成
    }

}
开庭审理测试Test.java:
import java.lang.reflect.Proxy;
public class Test {
    public static void main(String[] args) {
        //构造一个具体要诉讼的人:老罗
        ILawProtocol laoluo=new LaoLuo();
        /**使用静态代理**/
        //构造一个代理律师,并将老罗作为构造参数传进去
        ILawProtocol lawyer=new Lawyer(laoluo);
        //执行诉讼人的相关行为
        lawyer.submit();
        lawyer.burden();
        lawyer.defend();
        lawyer.finish();
    }
}
打印结果如下:
诉讼申请:西门子冰箱质量缺陷,特此申请民事仲裁!
诉讼证据:这是购买冰箱的发票,以及冰箱质量问题的视频!
诉讼辩护:我们证据确凿,必须得到应该的赔偿!
诉讼完成:判决西门子北京分公司在七日之内退还老罗购买冰箱的成本!

上文使用的是静态代理,但是静态代理后期扩展和维护比较困难,因为代码写的太死,没有可替换的余地;针对代码写得死能想到什么解决办法?对,就是反射。使用反射可以很到的解决决定加载哪个代理类的问题,避免了每个代理类都要重复写的问题,这就是动态代理。

新建一个动态代理类DynamicProxy .java:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicProxy implements InvocationHandler{
//继承InvocationHandler接口
    private Object obj;//被代理的类引用
    public DynamicProxy(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;
    }

}

然后修改客户类如下:

import java.lang.reflect.Proxy;
public class Test {
    public static void main(String[] args) {
        //构造一个具体要诉讼的人:老罗
        ILawProtocol laoluo=new LaoLuo();
        /**使用动态代理**/
        DynamicProxy dynamicProxy=new DynamicProxy(laoluo);//构造一个动态代理
        //获取被代理类老罗的ClassLoader
        ClassLoader loader=laoluo.getClass().getClassLoader();
        //动态的构造一个代理者律师类
        ILawProtocol lawyerT=(ILawProtocol)Proxy.newProxyInstance(
                loader, 
                new Class[]{ILawProtocol.class}, 
                dynamicProxy);
        //实现ILawProtocol的四个方法:
        lawyerT.submit();
        lawyerT.burden();
        lawyerT.defend();
        lawyerT.finish();
    }
}

打印结果同上。

代理模式除了分为静态代理和动态代理两种分法以外,还有其他按使用场景分类:

  • 远程代理(Remote Proxy): 为一个位于不同地址空间的的对象提供一个本地的代理。
  • 虚拟代理(Virtual Proxy):如果需要创建一个消耗较大的对象,先创建一个消耗较小的对象来表示,真实对象只在需要时才被真实创建。
  • 安全代理(Protection Proxy):用来控制对真实对象的访问权限

Android源码中的代理模式分析

Android源码中有不少的代理模式实现,比如源码里的ActivityManagerProxy代理类,其具体代理的是ActivityManagerNative的子类ActivityManagerService,ActivityManagerService 的功能是负责四大组件的启动/切换/调度、进程的管理/调度等; ActivityManagerService 继承自 ActivityManagerNative 类,并实现了 Watchdog.Monitor 和 BatteryStatsImpl.BatteryCallback 接口;而 ActivityManagerNative 继承自 Binder 类,并实现了 IActivityManager 接口。

class ActivityManagerProxy implements IActivityManager{
        //代码省略...
}

ActivityManagerProxy 实现了IActivityManager接口,该接口定义了Activity相关的接口方法,其中有一些我们在应用开发中也时常接触到。

public interface IActivityManager extends IInterface{
    public int startActivity(){};
    public Intent registerReceiver(){};
    public void unregisterReceiver(){};
    public ComponentName startService(){};
    public int stopService(){};
    public int bindService(){};
    //省略...
}

上面的IActivityManager这个接口类就相当于代理模式中的抽象主题,那么真正的实现主题是什么呢?就是上面我们提到的继承于ActivityManagerNative 的ActivityManagerService类,这几个类之间的关系如下:

android proxy Settings怎么配置_AMS_02

通过类图,我们可以清晰的看到ActivityManagerProxy和ActivityManagerNative 都实现了IActivityManager接口,严格的说ActivityManagerProxy就是代理部分,ActivityManagerNative 就是真实部分,但ActivityManagerNative 是一个抽象类,并不过多的处理具体逻辑,大部分具体逻辑由其子类ActivityManagerService承担。

ActivityManagerService是系统级的Service并且运行于独立的进程空间中,可以通过ServiceManager来获取它。而ActivityManagerProxy也是运行在独立的进程空间中,两者并不相同,因此ActivityManagerProxy与ActivityManagerService的通信必定是通过跨进程来进行的,从类图中也可以看到,这里跨进程的实现是基于Android的Binder机制,并且此处的代理模式实质是远程代理模式。

ActivityManagerProxy在实际的逻辑处理中并未过多的被外部类引用,因为在Android中管理和维护Activity相关信息的类是另外一个叫做ActivityManager的类,ActivityManager虽然说是管理者Activity的相关信息,但是实质上其大多数逻辑都是由ActivityManagerProxy承担。

下面的类关系图很好的描述了ActivityManagerProxy与ActivityManager之间的调用关系:

android proxy Settings怎么配置_代理模式_03

ActivityManagerService里的源码非常的复杂庞大,后续会继续学习并分享给大家。

总结

通过本篇文章需要掌握以下几点:
(1)代理模式的定义及使用场景,并会简单使用;
(2)理解动态代理和静态代理的区别;
(3)理解InvocationHandler和Proxy.newProxyInstance的使用;