美文网首页
Android设计模式---代理模式

Android设计模式---代理模式

作者: liys_android | 来源:发表于2019-08-23 18:13 被阅读0次
    一.核心思想

    为其他对象提供代理以控制对这个对象的访问,代理对象起到了中介作用,不影响其他对象原有的功能,可以在其基础上新增额外的服务。

    解释: A要访问a, A--->B(代理)--->a, 这个过程B代理可以做一些扩展性的东西, 而且不会影响a原有的功能.

    二. 分类

    1. 静态代理:
    2. 动态代理

    三. 简单实现

    例如: 计算吃饭时间
    如果不使用代理的情况

    public interface IDinner {
        String TAG = "66";
        void eat();
    }
    
    public class LiysBusiness implements IDinner {
        @Override
        public void eat() {
            Log.d(TAG, "开始时间: " +new Date().getTime());
            Log.d(TAG, "liys吃饭");
            Log.d(TAG, "结束时间: " +new Date().getTime());
        }
    }
    
    

    这种方式有个致命的缺点:
    如果想分别计算几百人吃饭的时间, 那重复的代码就多了去.
    下面我们看看怎么用代理模式解决这个问题的.

    1.静态代理

    public class LiysBusiness implements IDinner {
        @Override
        public void eat() {
            Log.d(TAG, "liys吃饭");
        }
    }
    
    public class HongDinner implements IDinner {
        @Override
        public void eat() {
            Log.d(TAG, "hong吃饭");
        }
    }
    

    代理类

    public class ProxyDinner implements IDinner {
    
        IDinner mIDinner;
    
        public ProxyDinner(@NonNull IDinner iDinner){
            this.mIDinner = iDinner;
        }
    
        @Override
        public void eat() {
            if(mIDinner != null){
                Log.d(TAG, "开始时间: " +new Date().getTime());
                mIDinner.eat();
                Log.d(TAG, "结束时间: " +new Date().getTime());
            }
        }
    }
    
    //使用
    //liys
    ProxyBusiness proxyDinner = new ProxyBusiness(new LiysBusiness());
    proxyDinner.handle();
    
    //hong
    proxyDinner = new ProxyBusiness(new HongBusiness());
    proxyDinner.handle();
    

    打印结果:


    log1.png

    这样就解决了上面的问题了.
    使用静态代理的好处:
    ①. 降低耦合性, 每个实现类只需要做属于自己的事情, 其它不需要管, 符合单一职责原则.
    ②. 扩展性强, 实现类的逻辑不用做任何改变, 即可实现, 符合开闭原则

    思考: 这样是不是就完美了呢? 如果我想计算洗澡的时间, 是不是还得写多一个洗澡的代理类ProxyBathe, 如果我还想计算睡觉的时间呢? 等等.这个时候代理类就会越来越多. 怎么办呢? 能不能用一个代理类解决这些问题? 这个时候就得看动态代理了.

    2. 动态代理
    Java里面其实为我们提供了一套动态代理机制, 我们先看关键类InvocationHandler(其实是一个接口).

    package java.lang.reflect;
    public interface InvocationHandler {
    
      /**
       * @param proxy 被代理的对象
       * @param method 被代理的方法
       * @param args 被代理方法参数
       * @return 返回代理对象
       * @throws Throwable
       */
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }
    

    下面看具体实现

    /**
     * 代理类(计算时间)
     */
    public class TimeInvocationHandler implements InvocationHandler{
    
        String TAG = "66";
        //被代理的对象
        private Object mObject;
    
        public TimeInvocationHandler(Object object){
            this.mObject = object;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Log.d(TAG, "开始时间: " +new Date().getTime());
            Object voidObject = method.invoke(mObject,args);
            Log.d(TAG, "结束时间: " +new Date().getTime());
            return voidObject;
        }
    }
    

    //新增洗澡功能

    public interface IBathe {
        String TAG = "66";
        void bathe();
    }
    
    public class Bathe implements IBathe{
        public void bathe(){
            try {
                Log.d(TAG, "洗澡..");
                Thread.sleep(123);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    

    //使用

    // 返回的是 IBank 的一个实例对象,这个对象是由 Java 给我们创建的 ,调用的是 jni
        //计算吃饭时间
        IDinner iDinner = (IDinner) Proxy.newProxyInstance(
                            IDinner.class.getClassLoader(), // ClassLoader
                            new Class<?>[]{IDinner.class}, // 目标接口
                            new TimeInvocationHandler(new LiysDinner()) //TimeInvocationHandler (这个类是关键)
        );
        iDinner.eat();
        
        //计算洗澡时间
        IBathe iBathe = (IBathe) Proxy.newProxyInstance(
                            IBathe.class.getClassLoader(),
                            new Class<?>[]{IBathe.class},
                            new TimeInvocationHandler(new Bathe())
        );
        iBathe.bathe();
    

    打印结果:


    log2.png

    这样就解决问题了, 以上就是动态代理的简单实现.
    如果想深入了解Proxy工作原理, 请参考: Proxy.newProxyInstance的秘密

    四. 实战篇

    源码这里只是大概介绍, 重点还是在动态代理
    Retrofit的创建
    首先我们看Retrofit最简单的运用, 用过的应该都能看懂.

    public interface ServiceApi {
    
        @POST("api/liys/login")// 登录接口 GET(相对路径)
        Call<User> userLogin(
                // @Query(后台需要解析的字段)
                @Query("userName") String userName,
                @Query("password") String userPwd);
    }
    
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("https://192.168.1.201")
                    .addConverterFactory(ScalarsConverterFactory.create()) //返回值解析成String
                    .build();
            // 创建一个 实例对象
            ServiceApi mServiceApi = retrofit.create(ServiceApi.class);
    
            mServiceApi.userLogin("123", "456")
                  .enqueue(new Callback<String>() {
                      @Override
                      public void onResponse(Call<String> call, Response<String> response) {}
                      @Override
                      public void onFailure(Call<String> call, Throwable t) {}
            });
    

    一开始看到这种用法的时候, 我一脸懵逼, 非常不习惯, 后面才慢慢习惯. 我们这里重点关注这行代码:

    ServiceApi mServiceApi = retrofit.create(ServiceApi.class);
    

    看看retrofit.create源码(版本:2.3.0): 省略部分代码

     public <T> T create(final Class<T> service) {
        //检测传进来的service是否是接口, 如果不是则抛出异常throw new IllegalArgumentException("API declarations must be interfaces.");
        Utils.validateServiceInterface(service);
    
        //动态代理(重点)
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
             
              @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                //执行接口上的方法时都要先进到这个方法里, 例如:mServiceApi.userLogin("123", "456")
                // 解析接口上的注解 和 方法参数, 经过一系列的操作,封装成Call或别的对象返回去
                return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
              }
            });
      }
    

    相关文章

      网友评论

          本文标题:Android设计模式---代理模式

          本文链接:https://www.haomeiwen.com/subject/omrpeqtx.html