Java设计模式(十八)—— 代理模式

Posted 小小印z

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java设计模式(十八)—— 代理模式相关的知识,希望对你有一定的参考价值。

一、模式简介        

代理模式定义如下:为其他对象提供一组代理以控制这对这个对象的访问。

适合代理模式的情景如下:

  • 不希望用户直接访问该对象,而是提供一个特殊的对象以控制对当前对象的访问
  • 如果一个对象需要很长时间才能加载完成
  • 如果对象位于远程主机上,需要为用户提供远程访问能力

代理模式包含如下角色:

  • ISubject:抽象主题角色,是一个接口,该接口是对象和它的代理所共用的接口
  • RealSubject:真实主题角色,是实现抽象主题接口的类
  • Proxy:代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象,同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。 

(1)定义抽象主题——买电视

public interface ITV 
    public void buyTV();

 (2)定义实际主题——买电视过程

public class Buyer implements ITV
    @Override
    public void buyTV() 
        System.out.println("我要通过代理来买电视");
    

(3)定义代理

电视代理商和购买者都实现了接口ITV,是对Buyer对象的进一步封装。

public class BuyerProxy implements ITV
    private Buyer buyer;

    public BuyerProxy(Buyer buyer) 
        this.buyer = buyer;
    

    @Override
    public void buyTV() 
        preProcess();
        buyer.buyTV();
        postProcess();
    
    public void preProcess() 
        System.out.println("询问客户需要的电视类型,价位等信息");
    
    public void postProcess() 
        System.out.println("负责把电视送到客户家");
    

(4)测试类

public class Test 
    public static void main(String[] args) 
        Buyer zy = new Buyer();
        BuyerProxy proxy = new BuyerProxy(zy);
        proxy.buyTV();
    

输出:

询问客户需要的电视类型,价位等信息
我要通过代理来买电视
负责把电视送到客户家

二、虚拟代理

        虚拟代理的关键思想是:如果需要创建一个资源消耗较大的对象,就先创建一个消耗相对较小的对象来表示,真实对象只要在需要时才会被真正创建。当用户请求一个“大”对象时,虚拟代理在该对象真正被创建出来之前扮演着替身的角色;当该对象被创建出来之后,虚拟代理就将用户的请求直接委托给该对象。

三、远程代理

        远程代理的含义是:为一个位于不同地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可以是另一台主机中,即远程对象驻留于服务器上,当客户机请求调用远程对象时调用相应方法,执行完毕后,结果由服务器返回给客户端。

        远程代理有两个代理,客户端通信代理和服务端通信代理。

《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.缺点

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

以上是关于Java设计模式(十八)—— 代理模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式_代理模式_动态代理

使用CGLib完成代理模式遇到的错误

java设计模式之代理模式:

Java 设计模式之代理模式,Java 静态代理,Java 动态代理

有关java的动态代理和代理模式

Java 之 设计模式——代理模式