• 一、模式定义
  • 二、模式结构
  • 三、时序图
  • 四、模式的简单实现
  • 五、代理模式在Binder中的使用
  • 六、优缺点
    • 优点
    • 缺点

    一、模式定义

    代理模式(Proxy Pattern) :给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。代理模式的英 文叫做Proxy或Surrogate,它是一种对象结构型模式。

    二、模式结构

    代理模式包含如下角色:

    • Subject: 抽象主题角色
    • Proxy: 代理主题角色
    • RealSubject: 真实主题角色

    代理模式 - 图1

    三、时序图

    代理模式 - 图2

    四、模式的简单实现

    抽象对象角色

    1. public abstract class AbstractObject {
    2. //操作
    3. public abstract void operation();
    4. }

    目标对象角色

    1. public class RealObject extends AbstractObject {
    2. @Override
    3. public void operation() {
    4. //一些操作
    5. System.out.println("一些操作");
    6. }
    7. }

    代理对象角色

    1. public class ProxyObject extends AbstractObject{
    2. RealObject realObject = new RealObject();
    3. @Override
    4. public void operation() {
    5. //调用目标对象之前可以做相关操作
    6. System.out.println("before");
    7. realObject.operation();
    8. //调用目标对象之后可以做相关操作
    9. System.out.println("after");
    10. }
    11. }

    客户端

    1. public class Client {
    2. public static void main(String[] args) {
    3. AbstractObject obj = new ProxyObject();
    4. obj.operation();
    5. }
    6. }

    五、代理模式在Binder中的使用

    直观来说,Binder是Android中的一个类,它继承了IBinder接口。从IPC角度来说,Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在linux中没有;从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager,etc)和相应ManagerService的桥梁;从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当你bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。

    Binder一个很重要的作用是:将客户端的请求参数通过Parcel包装后传到远程服务端,远程服务端解析数据并执行对应的操作,同时客户端线程挂起,当服务端方法执行完毕后,再将返回结果写入到另外一个Parcel中并将其通过Binder传回到客户端,客户端接收到返回数据的Parcel后,Binder会解析数据包中的内容并将原始结果返回给客户端,至此,整个Binder的工作过程就完成了。由此可见,Binder更像一个数据通道,Parcel对象就在这个通道中跨进程传输,至于双方如何通信,这并不负责,只需要双方按照约定好的规范去打包和解包数据即可。

    为了更好地说明Binder,这里我们先手动实现了一个Binder。为了使得逻辑更清晰,这里简化一下,我们来模拟一个银行系统,这个银行提供的功能只有一个:即查询余额,只有传递一个int的id过来,银行就会将你的余额设置为id*10,满足下大家的发财梦。

    1. 先定义一个Binder接口
    1. package com.ryg.design.manualbinder;
    2. import android.os.IBinder;
    3. import android.os.IInterface;
    4. import android.os.RemoteException;
    5. public interface IBank extends IInterface {
    6. static final String DESCRIPTOR = "com.ryg.design.manualbinder.IBank";
    7. static final int TRANSACTION_queryMoney = (IBinder.FIRST_CALL_TRANSACTION + 0);
    8. public long queryMoney(int uid) throws RemoteException;
    9. }

    2.创建一个Binder并实现这个上述接口

    1. package com.ryg.design.manualbinder;
    2. import android.os.Binder;
    3. import android.os.IBinder;
    4. import android.os.Parcel;
    5. import android.os.RemoteException;
    6. public class BankImpl extends Binder implements IBank {
    7. public BankImpl() {
    8. this.attachInterface(this, DESCRIPTOR);
    9. }
    10. public static IBank asInterface(IBinder obj) {
    11. if ((obj == null)) {
    12. return null;
    13. }
    14. android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    15. if (((iin != null) && (iin instanceof IBank))) {
    16. return ((IBank) iin);
    17. }
    18. return new BankImpl.Proxy(obj);
    19. }
    20. @Override
    21. public IBinder asBinder() {
    22. return this;
    23. }
    24. @Override
    25. public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
    26. throws RemoteException {
    27. switch (code) {
    28. case INTERFACE_TRANSACTION: {
    29. reply.writeString(DESCRIPTOR);
    30. return true;
    31. }
    32. case TRANSACTION_queryMoney: {
    33. data.enforceInterface(DESCRIPTOR);
    34. int uid = data.readInt();
    35. long result = this.queryMoney(uid);
    36. reply.writeNoException();
    37. reply.writeLong(result);
    38. return true;
    39. }
    40. }
    41. return super.onTransact(code, data, reply, flags);
    42. }
    43. @Override
    44. public long queryMoney(int uid) throws RemoteException {
    45. return uid * 10l;
    46. }
    47. private static class Proxy implements IBank {
    48. private IBinder mRemote;
    49. Proxy(IBinder remote) {
    50. mRemote = remote;
    51. }
    52. @Override
    53. public IBinder asBinder() {
    54. return mRemote;
    55. }
    56. public java.lang.String getInterfaceDescriptor() {
    57. return DESCRIPTOR;
    58. }
    59. @Override
    60. public long queryMoney(int uid) throws RemoteException {
    61. Parcel data = Parcel.obtain();
    62. Parcel reply = Parcel.obtain();
    63. long result;
    64. try {
    65. data.writeInterfaceToken(DESCRIPTOR);
    66. data.writeInt(uid);
    67. mRemote.transact(TRANSACTION_queryMoney, data, reply, 0);
    68. reply.readException();
    69. result = reply.readLong();
    70. } finally {
    71. reply.recycle();
    72. data.recycle();
    73. }
    74. return result;
    75. }
    76. }
    77. }

    ok,到此为止,我们的Binder就完成了,这里只要创建服务端和客户端,二者就能通过我们的Binder来通信了。这里就不做这个示例了,我们的目的是分析代理模式在Binder中的使用。

    我们看上述Binder的实现中,有一个叫做“Proxy”的类,它的构造方法如下:

    1. Proxy(IBinder remote) {
    2. mRemote = remote;
    3. }

    Proxy类接收一个IBinder参数,这个参数实际上就是服务端Service中的onBind方法返回的Binder对象在客户端重新打包后的结果,因为客户端无法直接通过这个打包的Binder和服务端通信,因此客户端必须借助Proxy类来和服务端通信,这里Proxy的作用就是代理的作用,客户端所有的请求全部通过Proxy来代理,具体工作流程为:Proxy接收到客户端的请求后,会将客户端的请求参数打包到Parcel对象中,然后将Parcel对象通过它内部持有的Ibinder对象传送到服务端,服务端接收数据、执行方法后返回结果给客户端的Proxy,Proxy解析数据后返回给客户端的真正调用者。很显然,上述所分析的就是典型的代理模式。至于Binder如何传输数据,这涉及到很底层的知识,这个很难搞懂,但是数据传输的核心思想是共享内存。

    六、优缺点

    优点

    • 给对象增加了本地化的扩展性,增加了存取操作控制

    缺点

    • 会产生多余的代理类