Android实用技巧-动态代理

应用场景

在Android的代码维护当中,经常会涉及到逻辑变更.但是又并不是整个逻辑变更了,往往是类似在之前的操作前面追加逻辑,或者是在之后追加逻辑.对于这样的逻辑,往往是每个类型的操作里面都要变更.
比较笨的方法当然就是挨个去写啦.但是这种体力劳动太低效,太浪费了.在JAVA中,针对这样的应用场景,比较常规的是有两种处理方案:
1.继承,重写方法;
2.装饰模式;
3.动态代理;

1.继承

对于这种方式,是最简单的方式.对于这个方式,大部分开发者都会很简单的就想到.但是这个方式会造成很大部分的垃圾代码,且灵活性并不高,而且还必须知道具体的类才能完成.示例如下:

1.1 写一个普通的类实现一个普通的方法

由于这里写在外面类比较麻烦,所以就直接在一个类中用静态内部类实现.

static class Man{
    public void run(){
        //一个正常人 跑步的方法
        System.out.println("the man is running !");
    }
}

1.2 写一个类继承这个类,进行增强

static class SuperMan extends Man{
    @Override
    public void run() {
        //super.run();
        System.out.println("the superMan is flying !");
    }
}

1.3 运行测试

       Man man = new SuperMan();
       man.run();

       //输出结果  the superMan is flying !

2.装饰模式

在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰者模式,在java中的实现是通过接口来定义,包装类和被包装类实现同一个接口,包装类持有被包装类对象,包装类就可以对被包装类实现增强了.

2.1 接口类定义

interface Waiter{
    void server();
}

2.2 被包装类实现

static class Waitress implements Waiter{

    @Override
    public void server() {
        System.out.println("Waitress server !");
    }
}

2.3 包装类实现

static class WaitessWrapper implements Waiter{

    public Waiter waiter;

    public WaitessWrapper(Waiter waiter) {
        //为了通用  持有接口类
        this.waiter = waiter;
    }

    @Override
    public void server() {
        System.out.println("smile");
        waiter.server();
        System.out.println("smile end !");
    }
}

2.4 调用函数

    Waiter waiter1 = new Waitress();
    waiter1.server();
    Waiter waiter2 = new WaitessWrapper(waiter1);
    waiter2.server();
    //结果显示如下

Waitress server !

smile
Waitress server !
smile end !

3.动态代理

代理机制及特点
1.通过实现 InvocationHandler 接口创建自己的调用处理器;
2.通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
3.通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
4.通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

由于主要目的是实现Android中的应用,因此我就直接附上项目代码进行说明:

 private void initListener() {


    Object object = Proxy.newProxyInstance(this.getClass()
                                               .getClassLoader(),
                                           this.getClass()
                                               .getInterfaces(),
                                           (Object proxy, Method method, Object[] args) -> {
                                               switch (method.getName()) {
                                                   case "onCategory":
                                                   case "onName":
                                                   case "onShare":
                                                   case "onPic":
                                                   case "onItemClick":
                                                   case "onRefresh":
                                                   case "onClick":
                                                   case "onOptionsItemSelected":
                                                   case "onNavigationItemSelected":
                                                       if (isEnvent) {
                                                           return null;
                                                       }
                                                       return method.invoke(NavActivity.this,
                                                                            args);

                                                   case "onOption":
                                                       if (isEnvent) {
                                                           return null;
                                                       }
                                                       if (!TDevice.hasInternet()) {
                                                           showErrorTip(getString(R.string.footer_type_net_error));
                                                           return null;
                                                       }
                                                       if (WXShareManager.sWXAPI.getWXAppSupportAPI() <= WXShareManager.TIMELINE_SUPPORTED_VERSION) {
                                                           AppContext.showToast(R.string.weixin_update);
                                                           return null;
                                                       }
                                                       return method.invoke(NavActivity.this,
                                                                            args);

                                               }
                                               return method.invoke(NavActivity.this, args);
                                           });

    mNavView.setNavigationItemSelectedListener((NavigationView.OnNavigationItemSelectedListener) object);
    mFgtMainSrl.setOnRefreshListener((SwipeRefreshLayout.OnRefreshListener) object);
    mAdapter.setListener((FileItemAdapter.OnFileItemListener) object);
    mCreate.setOnClickListener((View.OnClickListener) object);
    mScrollListener = new ScrollListener(null);
    mFgtMainRv.addOnScrollListener(mScrollListener);
    mCiv.setOnClickListener((View.OnClickListener) object);
    mTvUser.setOnClickListener((View.OnClickListener) object);
    mFusion.setOnClickListener((View.OnClickListener) object);
    mDelete.setOnClickListener((View.OnClickListener) object);
    mSeletedAll.setOnClickListener((View.OnClickListener) object);
}

如上,是我项目中的代码.简单说明一下:
1.标记位 isEnvent 是项目中当前是否有操作,在有操作的情况下应该避免别的操作.
2.Proxy.newProxyInstance 返回值 Object 是返回的当前操作执行返回的接口对象.
3.Proxy.newProxyInstance 中参数说明:如下是方法声明

  public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException{}

参数一:ClassLoader loader 类加载器
参数二:Class<?>[] interfaces 代理接口
参数三:InvocationHandler h 对于代理接口的处理对象,主要代码逻辑在这个类中实现,处理逻辑详细看上述例子.

这样实现可以最大限度的简化代码,解耦.而且这样改起来也很方便.在后续代码逻辑的变化中,主要逻辑写在接口方法实现中,追加的逻辑都写在代理对象里面.可以方便随时更改,而且比较统一,找起来也不复杂.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章