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);
}
[java] view plain copy
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)等,学习设计模式其实最适合的方法就是拿来用,在适用于该模式的场景下灵活得去运用它才算是真正的掌握一种模式.

您可能感兴趣的文章:

  • android设计模式之单例模式详解
  • Android开发中的MVC设计模式浅析
  • 基于Android设计模式之--SDK源码之策略模式的详解
  • Android应用开发中控制反转IoC设计模式使用教程
  • Android设计模式之适配器(Adapter)模式
  • Android 单例模式 Singleton 简单实例设计模式解析
  • Android设计模式系列之组合模式
  • Android设计模式系列之工厂方法模式
  • Android中的设计模式
  • android开发设计模式之——单例模式详解
(0)

相关推荐

  • android设计模式之单例模式详解

    这是我们最常见的一类模式,对这一类模式有一个通用的特点就是: 封装创建的方式和过程. 这里所谓封装就是隐藏的意思,对对象的创建方法和过程不可见,或者是虚拟的过程. 隐藏创建方式,就是如单例,工厂方法,隐藏创建过程则是指builder,原型,至于抽象工厂,我认为他包含了以上两种. 我们想想一个对象的创建有哪些步骤? 1.创建什么东西?--接口定义 2.谁创建?        --决策类or帮助类 3.如何创建?     --how,创建过程 4.什么时候创建?    --创建时机的触发 由此可知,

  • Android设计模式系列之组合模式

    Android中对组合模式的应用,可谓是泛滥成粥,随处可见,那就是View和ViewGroup类的使用.在android UI设计,几乎所有的widget和布局类都依靠这两个类. 组合模式,Composite Pattern,是一个非常巧妙的模式.几乎所有的面向对象系统都应用到了组合模式. 1.意图 将对象View和ViewGroup组合成树形结构以表示"部分-整体"的层次结构(View可以做为ViewGroup的一部分). 组合模式使得用户对单个对象View和组合对象ViewGrou

  • Android开发中的MVC设计模式浅析

    Android开发中的MVC设计模式的理解 1. Android系统中分层的理解: (1).在Android的软件开发工作中,应用程序的开发人员主要是应用Android Application Framework层封装好的Api进行快速开发. (2).在Android框架的四个层次中,下层为上层服务,上层需要下层的支持,上层需要调用下层的服务. (3).这种分层的方式带来极大的稳定性.灵活性和可扩展性,使得不同层的开发人员可以按照规范专心特定层的开发. (4). Android的官方建议应用程序

  • Android中的设计模式

    一般来说,常用的设计模式有以下八种:单例.工厂.观察者.代理.命令.适配器.合成.访问者 单例模式:目的是为了让系统中只有一个调用对象,缺点是单例使其他程序过分依赖它,而且不同单例运行在不同进程中,使得维护困难: 工厂模式:生产固定的一些东西,如抽象类,缺点是产品修改麻烦:如喜欢动作片和爱情片的人分别向服务器发出同一个请求,就可以得到他们想看的影片集,相当于不同对象进行同一请求,需求均得到满足. 观察者模式:就是多个对象对一个对象进行监控,如缓存: 代理模式:自己的事交给别人去做,分别返回结果即

  • Android应用开发中控制反转IoC设计模式使用教程

    1.概述 首先我们来吹吹牛,什么叫IoC,控制反转(Inversion of Control,英文缩写为IoC),什么意思呢? 就是你一个类里面需要用到很多个成员变量,传统的写法,你要用这些成员变量,那么你就new 出来用呗~~ IoC的原则是:NO,我们不要new,这样耦合度太高:你配置个xml文件,里面标明哪个类,里面用了哪些成员变量,等待加载这个类的时候,我帮你注入(new)进去: 这样做有什么好处呢?  回答这个问题,刚好可以回答另一个问题,很多人问,项目分层开发是吧,分为控制层.业务层

  • android开发设计模式之——单例模式详解

    单例模式是设计模式中最常见也最简单的一种设计模式,保证了在程序中只有一个实例存在并且能全局的访问到.比如在Android实际APP 开发中用到的 账号信息对象管理, 数据库对象(SQLiteOpenHelper)等都会用到单例模式.下面针对一些例子分析一下我们在开发过程中应用单例模式需要注意的点.  一.作用 单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点 二.适用场景 1. 应用中某个实例对象需要频繁的被访问. 2. 应用中每次启动只会存在一个实例.如账号

  • Android设计模式系列之工厂方法模式

    工厂方法模式,往往是设计模式初学者入门的模式,的确,有人称之为最为典型最具启发效果的模式. android中用到了太多的工厂类,其中有用工厂方法模式的,当然也有很多工厂并不是使用工厂方法模式的,只是工具管理类. 今天以ThreadFactory举例说明一下简单工厂模式和工厂方法模式. 工厂方法模式,Factory Method,简单的方式,不简单的应用. 1.意图 定义一个用于创建对象的接口,让子类决定实例化哪个类.工厂方式模式使一个类的实例化延迟到其子类. 热门词汇:虚构造器 延迟 创建对象

  • Android 单例模式 Singleton 简单实例设计模式解析

    单例模式 Singleton 简单实例设计模式解析 前言 今天我来全面总结一下Android开发中最常用的设计模式 - 单例模式. 关于设计模式的介绍,可以看下我之前写的:1分钟全面了解"设计模式" 目录 1. 引入 1.1 解决的是什么问题 之前说过,设计模式 = 某类特定问题的解决方案,那么单例模式是解决什么问题的解决方案呢? 含义:单例 =一个实例: 解决的问题:降低对象之间的耦合度 解决方法:单例模式,即实现一个类只有一个实例化对象,并提供一个全局访问点 1.2 实例引入 接下

  • Android设计模式之适配器(Adapter)模式

    本文实例为大家分享了Android适配器模式源码,供大家参考,具体内容如下 1. 模式介绍 1.1模式的定义: 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 1.2模式的使用场景: 用电源接口做例子,笔记本电脑的电源一般都是接受5V的电压,但是我们生活中的电线电压一般都是220V的输出.这个时候就出现了不匹配的状况,在软件开发中我们称之为接口不兼容,此时就需要适配器来进行一个接口转换.在软件开发中有一句话正好体现了这点:任

  • 基于Android设计模式之--SDK源码之策略模式的详解

    策略模式其实特别简单(听到这句话,大家是不是心里一下子放松了?).比如排序,官方告诉大家我这里有一个排序的接口ISort的sort()方法,然后民间各尽其能,实现这个排序的方法:冒泡,快速,堆等等.这些方法就是"不同的策略".然后,某个模块下,需要一个排序方法,但是暂时不能指定具体的sort方法(出于扩展的考虑),就需要使用ISort接口了.最后,具体什么场景下,传入什么具体的sort方法,实现灵活的排序.这就是策略模式!下面,我们分析Android中的动画是如何使用策略模式的. 1.

随机推荐