`
iaiai
  • 浏览: 2204170 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android设计模式之代理模式 Proxy

 
阅读更多
一.概述
       代理模式也是平时比较常用的设计模式之一,代理模式其实就是提供了一个新的对象,实现了对真实对象的操作,或成为真实对象的替身.在日常生活中也是很常见的.例如A要租房,为了省麻烦A会去找中介,中介会替代A去筛选房子,A坐享中介筛选的结果,并且交房租也是交给中介,这就是一个典型的日常生活中代理模式的应用.平时打开网页,最先开到的一般都是文字,而图片等一些大的资源都会延迟加载,这里也是使用了代理模式.

       代理模式的组成:

       Abstract Subject:抽象主题-声明真实主题和代理主题共同的接口

       Real Subject:真实主题-真实的对象,需要被代理主题引用

       Proxy Subject:代理主题-因为ProxySubject引用了RealSubject,并且实现了跟RealSubject一样的接口,所以ProxySubject可以操作RealSubject,还可以提供一些附加操作,例如before & after

       代理模式常用基于场景的分类:

       1.Virtual Proxy:虚拟代理其实就是通过代理的模式对消耗资源比较大的对象做了一个延迟加载,就是什么时候用到这个对象才去创建它.

       2.Remote Proxy:远程代理是比较经典的应用了,类似于C/S模式(主要拦截并控制远程方法的调用,做代理防火墙之类的).

       3.Smart Reference Proxy:智能引用代理可以给引用的对象提供一些额外的操作,例如实现里面中介Searching和Prepare contract的动作.

       4.Access Proxy;保护代理可以控制一个对象的访问,必要时候提供一系列的权限管理.

       5.Copy-on-write Proxy:写时拷贝(克隆)代理其实是Virtual Proxy的分支,提供了拷贝大对象的时候只有在对象真正变化后才会进行拷贝(克隆)的操作(延迟拷贝).


       代理模式的优缺点:

       优点:

       1.代理作为调用着和真实对象的中间层,降低了模块间和系统的耦合性

       2.可以以一个小对象代理一个大对象,达到优化系统提高运行速度的目的

       3.提供RealSubject的权限管理

       4.容易扩展,RealSubject和ProxySubject都接口化了,RealSubject更改业务后只要接口不变,ProxySubject可以不做任何修改.

       缺点:

       1.同优点1,因为调用者和真实对象多了一个中间层,所以会增加调用响应的时间

二.实现
       这里就拿A找中介租房为Demo来构建代理模式.

1.普通代理

       根据场景先定义一个抽象主题,IHouse,提供三个方法,分别是获取房屋信息,签合同和付租金.
/** 
 * Created by jesse on 15-7-24. 
 */  
public interface IHouse {  
    void getHouseInfo();  
    void signContract();  
    void payFees();  
}

       接下来定义真实主题,并实现IHouse接口.增加房屋名称和价格两个属性,填充借口方法,在获取房屋信息的时候就把房屋名称和价格log出来;签合同的时候log出签合同的时间,付租金的时候log出价格.
public class House implements IHouse{  
    private final String TAG = House.class.getSimpleName();  
    private String name;  
    private double price;  
  
    public House(String name, double price){  
        this.name = name;  
        this.price = price;  
    }  
  
    @Override  
    public void getHouseInfo() {  
        Log.i(TAG, "House Info- name:" + name + "  ¥:" + price);  
    }  
  
    @Override  
    public void signContract() {  
        Log.i(TAG, "Contract:" + name + "  signed at" +  
               new SimpleDateFormat("HH:mm:ss").format(SystemClock.uptimeMillis()));  
    }  
  
    @Override  
    public void payFees() {  
        Log.i(TAG, "Bill: name-" + name + "  $-" + price);  
    }  
}

       定义房屋代理,同样需要实现IHouse接口,并持有House的引用.可以看到代理类其实就像有封装House,提供了一些附加操作,例如客户要看房子的时候代理会先检索自己库存的房屋信息,签合同之前要准备合同之类的.
public class ProxyHouse implements IHouse{  
    private final String TAG = ProxyHouse.class.getSimpleName();  
    private IHouse house;  
    public ProxyHouse(IHouse house){  
        this.house = house;  
    }  
    @Override  
    public void getHouseInfo() {  
        Log.i(TAG, "searching");  
        house.getHouseInfo();  
        Log.i(TAG, "search finished");  
    }  
  
    @Override  
    public void signContract() {  
        Log.i(TAG, "prepare contract");  
        house.signContract();  
    }  
  
    @Override  
    public void payFees() {  
        house.payFees();  
    }  
}

       对于客户来说,完全不用跟House进行直接交互,这里先定义一个房子叫唐顿庄园,租金5k,建立一个房屋代理,把唐顿庄园委托给代理.客户要找房子,签合同,付租金直接找代理就行了.
IHouse house = new House("Downton Abbey", 5000);  
IHouse proxyHouse = new ProxyHouse(house);  
Log.i(TAG, "looking for a perfect house");  
proxyHouse.getHouseInfo();  
Log.i(TAG, "thinking");  
proxyHouse.signContract();  
proxyHouse.payFees();  
Log.i(TAG, "so easy");


       整个代理模式的流程可以从下面的时序图展示出来.Client只跟代理进行交互.

2.虚拟代理

       虚拟代理前面有介绍,就是基于代理模式又做了延迟加载来节省内存,但是如果某个对象要在多个没有固定时序地方使用的时候就要进行判空,也会一定程度上牺牲性能(有点像代理模式+懒汉模式).这里还是拿租房的例子来展示.

       这里就假设House是一个很庞大的对象,在创建的时候很耗费资源,那我们就更改成当Custom需要用它的时候才去初始化.这里就在ProxyHouse构造的时候先判House的引用是否为空,然后才会初始化House,当然如果这里有多线程并发的话可以根据不同的场景进行加锁或者双检锁来保证线程安全.
public ProxyHouse(){  
    if (null == house)  
        house = new House("Downton Abbey", 5000);  
}

IHouse proxyHouse = new ProxyHouse();  
Log.i(TAG, "looking for a perfect house");  
proxyHouse.getHouseInfo();  
Log.i(TAG, "thinking");  
proxyHouse.signContract();  
proxyHouse.payFees();  
Log.i(TAG, "so easy");

3.强制代理
       强制代理是反其道而行之的代理模式,一般情况下代理模式都是通过代理来找到真实的对象,而强制代理则是通过真实对象才能找到代理也就是说由真实对象指定代理,当然最终访问还是通过代理模式访问的.从名字还能看出它跟其他代理的一个不同,就是强制用代理.拿上面普通代理的例子来说,Custom看不到实体的House的时候它只能通过代理来访问,但是由于没有限制,Custom也可以直接绕过ProxyHouse来访问House,但是强制代理就多了一个限制,Custom必须通过ProxyHouse才能访问House.就像一些房东嫌麻烦,有房客直接电话过来说要看房,房东给出一个中介的电话说你跟中介联系吧.

       首先需要在接口里面添加一个获取代理的接口
public interface IHouse {  
    void getHouseInfo();  
    void signContract();  
    void payFees();  
    IHouse getProxy();  
}

       真实对象实现接口,并在getProxy中实例化代理,同时在其他方法里面做代理判断,只有使用自身自定的代理才会正常进行.
public class House implements IHouse{  
    private final String TAG = House.class.getSimpleName();  
    private String name;  
    private double price;  
    private IHouse proxy;  
  
    public House(String name, double price){  
        this.name = name;  
        this.price = price;  
    }  
  
    @Override  
    public void getHouseInfo() {  
        if (isProxy())  
            Log.i(TAG, "House Info- name:" + name + "  ¥:" + price);  
        else  
            Log.i(TAG, "Please use correct proxy");  
    }  
  
    @Override  
    public void signContract() {  
        if (isProxy())  
            Log.i(TAG, "Contract:" + name + "  signed at" +  
                    new SimpleDateFormat("HH:mm:ss").format(SystemClock.uptimeMillis()));  
        else  
            Log.i(TAG, "Please use correct proxy");  
  
    }  
  
    @Override  
    public void payFees() {  
        if (isProxy())  
            Log.i(TAG, "Bill: name-" + name + "  $-" + price);  
        else  
            Log.i(TAG, "Please use correct proxy");  
    }  
  
    @Override  
    public IHouse getProxy() {  
        if (null == proxy)  
            proxy = new ProxyHouse(this);  
        return proxy;  
    }  
  
    private boolean isProxy(){  
        if (null == proxy)  
            return false;  
        else  
            return true;  
    }  
}

       如果这个时候直接操作House对象,或者通过Custom构建的代理来访问都会返回以下结果

       所以我们必须使用由真实对象指定的代理才可以正常得访问.
IHouse house = new House("Downton Abbey", 5000);  
house = house.getProxy();  
Log.i(TAG, "looking for a perfect house");  
house.getHouseInfo();  
Log.i(TAG, "thinking");  
house.signContract();  
house.payFees();

       但是这里的强制代理有个Bug,强制代理其实并没有生效,Custom还是可以直接访问House,例如我通过下面的方式来进行访问,只是通过getProxy创建并获取代理,但是我不用代理还是直接用House的实例进行访问,这个时候还是可以正常访问的.后续会想办法解了这个Bug并且更新上来的.
IHouse house = new House("Downton Abbey", 5000);  
house.getProxy();//这里只是通过getProxy创建出代理  
Log.i(TAG, "looking for a perfect house");  
house.getHouseInfo();  
Log.i(TAG, "thinking");  
house.signContract();  
house.payFees();

4.动态代理

       上面介绍的都是自己先写好的代理类,这样代理关系都是固定的,当代理多个真实对象的时候就要写多个代理类,并且会产生冗余的代码,扩展性和可维护性都不高,而动态代理是基于反射实现了在程序运行的过程中才决定代理什么对象.像AOP的核心思想就是动态代理.(这里使用的是Java的动态代理)
       既然是动态代理就不需要ProxyHouse也不需要实现IHouse接口了,这里写一个ProxyHandler实现InvocationHandler的invoke接口,并且提供一个根据Proxy构建出来的代理实例给Custom.在通过反射调用真实对象具体的方法之前打印出该方法的名字.
public class ProxyHandler implements InvocationHandler{  
    private final String TAG = ProxyHandler.class.getSimpleName();  
    Object targetObj;  
  
    public Object newProxyInstance(Object targetObj){  
        this.targetObj = targetObj;  
        return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(),  
                    targetObj.getClass().getInterfaces(), this);  
    }  
  
    @Override  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        Object ret;  
        Log.i(TAG, "method name:" + method.getName());  
        ret = method.invoke(targetObj, args);  
        return ret;  
    }  
}

ProxyHandler proxy = new ProxyHandler();  
IHouse house = (IHouse) proxy.newProxyInstance(new House("Downton Abbey", 5000));  
Log.i(TAG, "looking for a perfect house");  
house.getHouseInfo();  
Log.i(TAG, "thinking");  
house.signContract();  
house.payFees();  
Log.i(TAG, "so easy");

       从结果可以看出在真正invoke真实对象的方法之前都会打印出方法名,也可以在这里做一些其他的对象控制.

       这个时候整个过程的时序图就变成下面的样子了,通过JDK的Proxy对象和反射的机制来支撑起来动态代理的核心功能.

三.总结
       代理模式的使用场景还是挺多的,可以降低对象的复杂度,对项目进行解耦(特别是动态代理的AOP)等,学习设计模式其实最适合的方法就是拿来用,在适用于该模式的场景下灵活得去运用它才算是真正的掌握一种模式.
  • 大小: 24.3 KB
  • 大小: 10.2 KB
  • 大小: 35.6 KB
  • 大小: 8.1 KB
  • 大小: 11 KB
  • 大小: 32.4 KB
分享到:
评论

相关推荐

    Android设计模式之代理模式(Proxy Pattern)

    在软件工程中,设计模式是一种解决常见问题的模板或最佳实践,它被广泛应用于各种编程语言,包括Android开发。代理模式是设计模式的一种,它的主要目的是在不改变原有对象的基础上,为一个对象提供额外的功能或者...

    android设计模式之代理模式

    代理模式在软件设计中是一种常用的设计模式,尤其在Android开发中,它可以帮助我们实现复杂的控制逻辑,隔离复杂性,以及提供额外的功能。在Android上下文中,代理模式常常用于数据加载、权限控制、事件处理等方面。...

    Android设计模式之代理模式Proxy浅显易懂的详细说明

    代理模式也是平时比较常用的设计模式之一,代理模式其实就是提供了一个新的对象,实现了对真实对象的操作,或成为真实对象的替身.在日常生活中也是很常见的.例如A要租房,为了省麻烦A会去找中介,中介会替代A去筛选房子,A...

    Android-23种设计模式

    9. **代理模式(Proxy)**:为其他对象提供一种代理以控制对这个对象的访问。Android的`AsyncTask`在异步操作中起到了代理的作用。 10. **观察者模式(Observer)**:定义对象间的一对多依赖关系,当一个对象的状态改变...

    Android源码设计模式

    5. **代理模式** (Proxy): `AsyncTask`是Android中的代理模式应用,它允许在后台线程执行任务,同时在UI线程更新结果,避免了主线程阻塞。 6. **装饰者模式** (Decorator): Android的`InputStream`和`OutputStream`...

    android 源码设计模式

    6. **代理模式(Proxy)**:比如`ContentProvider`,它作为数据访问的代理,允许不同应用之间安全地共享数据。 7. **装饰者模式(Decorator)**:在Android中,`LayoutInflater.Factory`和`LayoutInflater.Factory2...

    android 24种设计模式介绍与6大设计原则

    在Android开发中,设计模式和设计原则是提升代码质量、可维护性和可扩展性的重要工具。以下是关于"Android 24种设计模式介绍与6大设计原则"的详细阐述: 一、六大设计原则 1. **单一职责原则(Single ...

    android设计模式

    8. **AndroidDemo** - 这可能是一个综合性的示例,包含了多种设计模式的应用,例如`工厂模式`(Factory Pattern)、`适配器模式`(Adapter Pattern)或`代理模式`(Proxy Pattern),用于创建对象、接口转换和远程...

    中文版_源码设计模式解析与实战.pdf

    3. **结构型模式**:包括适配器模式(Adapter)、装饰器模式(Decorator)、代理模式(Proxy)、桥接模式(Bridge)、组合模式(Composite)、外观模式(Facade)和享元模式(Flyweight)。这些模式主要处理类和对象...

    安卓设计模式之代理模式

    在Android开发中,设计模式是一种重要的编程思想,它能够帮助我们编写更加灵活、可维护的代码。代理模式作为其中一种,常被用于控制对对象的访问或者为对象添加额外的功能。本文将深入探讨代理模式在Android环境下的...

    android设计招式之美(全)

    《Android设计招式之美》是一本深入探讨Android框架设计模式的专业书籍,涵盖了从基础到高级的各种设计技巧。这本书通过对各种设计模式的详细讲解,旨在帮助开发者提升在Android平台上的编程能力,实现更高效、可...

    Android-用Kotlin实现设计模式代码

    6. **代理模式(Proxy)**:在Android中,代理模式常用于权限检查、数据缓存、事件总线等场景。例如,网络请求的拦截器可以作为代理,添加额外的处理逻辑。 7. **适配器模式(Adapter)**:将不同接口转换为统一接口,...

    设计模式源码.zip

    结构型模式关注如何组合和构建类或对象,如适配器模式(Adapter)、装饰器模式(Decorator)和代理模式(Proxy)。行为型模式则关注对象之间的交互和责任分配,如观察者模式(Observer)、策略模式(Strategy)和...

    Android源码设计模式解析与实战 pdf 版

    其次,结构型设计模式,如适配器模式(Adapter)、代理模式(Proxy)和装饰器模式(Decorator),在Android UI组件和数据绑定中起着关键作用。适配器模式使得不同的接口能够协同工作,如ListView的Adapter将数据源...

    Android源码设计模式解析与实战

    Android源码设计模式解析与实战是一本关于Android开发的高级技术...它不仅能帮助读者从宏观角度掌握设计模式的精髓,也能通过实例分析和实战演练,加深对Android源码设计思想的理解,从而更好地应用于实际开发之中。

    Android Head First 设计模式高清版本

    本书主要聚焦于Android移动开发中的设计模式学习与实践,是Android开发者从入门到精通的重要参考资料之一。 ### 关键知识点概述 #### 一、设计模式的概念及意义 设计模式是一种在特定场景下对软件设计问题的解决...

    Android 中常用设计模式

    工厂模式也是创建型设计模式之一,主要用于创建对象而不暴露创建逻辑,通过使用一个共同的接口来指向新创建的对象。 - **工厂方法模式** - **普通工厂模式** 创建一个工厂类,负责创建实现了同一接口的多个类的...

    android 毕业设计,Xml解析和设计模式应用了高保真界面设计。

    在这个项目中,提到了五种设计模式的使用,虽然具体是哪五种没有明确指出,但常见的设计模式如单例模式(Singleton)、工厂模式(Factory)、观察者模式(Observer)、适配器模式(Adapter)和代理模式(Proxy)都...

    初中级Android开发社招面试之设计模式.zip

    在Android开发领域,设计模式是面试中不可或缺的一部分,尤其对于初中级开发者来说,掌握和理解设计模式至关重要。设计模式是经过实践验证的解决方案,用于解决软件设计中常见问题的模板,能够提高代码的可读性、可...

    Java设计模式demo

    代理模式(Proxy)为其他对象提供一种代理以控制对这个对象的访问,以及外观模式(Facade)提供了一个统一的接口,用来访问子系统的一组接口。 行为型模式关注于对象之间的责任分配,比如命令模式(Command)将请求...

Global site tag (gtag.js) - Google Analytics