首页 > 代码库 > 《Android源代码设计模式解析与实战》读书笔记(十八)

《Android源代码设计模式解析与实战》读书笔记(十八)

第十八章、代理模式

代理模式也称托付模式,是结构型设计模式之中的一个。是应用广泛的模式之中的一个。

1.定义

为其它对象提供一种代理以控制对这个对象的訪问。

2.使用场景

当无法或不想直接訪问某个对象或訪问某个对象存在困难时能够通过一个代理对象来间接訪问,为了保证client使用的透明性。托付对象与代理对象须要实现相同的接口。

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)代理对象在client和目标对象之间起到一个中介的作用,这样能够起到对目标对象的保护。

2.缺点

基本没有缺点,真要说缺点就是设计模式的通病:对类的添加。

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

《Android源代码设计模式解析与实战》读书笔记(十八)