Use chain of responsibility model to transform code processing filtering

Scene introduction

When the application enters the foreground from the background, it jumps to the startup page to display the on-screen advertisement, which is a relatively common scenario. Often we need to add some control conditions, not all cases will skip the screen ads, then the user experience will be poor, so there will be a series of filter conditions.

Initial plan

At first it was like this:

  1. Determine whether you need to block back from a certain page
  2. Judgment channel
  3. Control interval time and frequency limit according to interface content
       if (activity instanceof SplashActivity) {
            //启动页
            return;
        }
        if (activity instanceof LockScreenActivity) {
            //锁屏
            return;
        }
        if (activity instanceof AlcWidgetBaseConfigActivity) {
            //组件设置
            return;
        }
        if(AlcChannelUtil.isHuawei(this)){
            return;
        }
        String data = OnlineData.getInstance().getKey(activity, "go_splash_open", "");
        int status = 0;
        int oneDayMaxCount = 5;
        //120秒
        int offsetTime = 60;
        if (!TextUtils.isEmpty(data)) {
            try {
                JSONObject object = new JSONObject(data);
                status = object.optInt("isOpen");
                offsetTime = object.optInt("offsetTime");
                oneDayMaxCount = object.optInt("oneDayMaxCount");
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        boolean isOpen = status == 1;
        //转成毫秒
        offsetTime = offsetTime * 1000;
        if (isOpen) {
            //如果打开
            long lastSplashTime = (long) SPUtils.get(activity, "lastSplashTime", 0L);
            //并且时间间隔大于设置的时间间隔
            if ((System.currentTimeMillis() - lastSplashTime) > offsetTime) {
                //再判断次数是否达到上限
                //判断是否是今天
                int todayOpenCount = 0;
                if (TimeUtils.isSameDay(lastSplashTime)) {
                    todayOpenCount = (int) SPUtils.get(activity, "todayOpenCount", 0);
                }
                if (todayOpenCount < oneDayMaxCount) {
                    //小于这个次数,进入开屏页,保存这一次的时间,更新今天展开次数
                    SPUtils.put(activity, "lastSplashTime", System.currentTimeMillis());
                    todayOpenCount++;
                    SPUtils.put(activity, "todayOpenCount", todayOpenCount);
                    Intent goSplash = new Intent(activity, SplashActivity.class);
                    goSplash.putExtra("isFromOtherApp", true);
                    activity.startActivity(goSplash);
                }
            }
        }

All written in one place, the code is bloated, and the scalability is also poor. If you add or delete conditions later, you will directly modify it here. It feels inappropriate, so I thought of using the chain of responsibility model to transform it.

Improve

Define basic classes

First define three basic classes, one is the interceptor interface, one is Chain used to connect all interceptors, and the other is the object bean processed by the interceptor.

public interface BaseSplashAdInterceptor {
    /**
     * 进行处理过滤,比如修改是否跳转广告、修改广告类型等
     *
     * @param adStatusBean
     */
    void doProcess(SplashAdStatusBean adStatusBean);
}

Chain class

public class SplashAdChain {
    private List<BaseSplashAdInterceptor> mChains;

    /**
     * 添加拦截器
     * @param interceptor
     * @return
     */
    public SplashAdChain addInterceptor(BaseSplashAdInterceptor interceptor) {
        if (mChains == null) {
            mChains = new ArrayList<>();
        }
        mChains.add(interceptor);
        return this;
    }

    /**
     * 处理拦截操作
     * @param adStatusBean
     */
    public void doProcess(SplashAdStatusBean adStatusBean) {
        if (mChains != null) {
            for (BaseSplashAdInterceptor interceptor : mChains) {
                interceptor.doProcess(adStatusBean);
            }
        }
    }
}

Operation object class:

public class SplashAdStatusBean implements Serializable {
    /**
     * 是否要跳转启动页广告
     */
    private boolean isNeedGoSplashAd;
    /**
     * 广告类型
     */
    private int splashAdType;
    /**
     * 从哪里来的
     */
    private Activity currentActivity;
    //...set和get方法 ,构造方法等
}

Set interceptor

Then set up the interceptor according to the required conditions, for example:

/**
 * 过滤Activity
 *
 * @author moore
 * @date 2019/8/5
 */
public class SplashAdActivityInterceptor implements BaseSplashAdInterceptor {

    @Override
    public void doProcess(SplashAdStatusBean adStatusBean) {
        if (adStatusBean.isNeedGoSplashAd()) {
            //如果需要跳转,再进行过滤
            Activity currentActivity = adStatusBean.getCurrentActivity();
            if (currentActivity == null) {
                adStatusBean.setNeedGoSplashAd(false);
                return;
            }
            if (currentActivity instanceof SplashActivity) {
                //启动页
                adStatusBean.setNeedGoSplashAd(false);
                return;
            }
            if (currentActivity instanceof LockScreenActivity) {
                //锁屏
                adStatusBean.setNeedGoSplashAd(false);
                return;
            }
            if (currentActivity instanceof AlcWidgetBaseConfigActivity) {
                //组件设置
                adStatusBean.setNeedGoSplashAd(false);
                return;
            }
        }
    }
}

The other conditions are the same, move him to the interceptor to operate, and classify them. Like controlling the time, controlling the number of times, controlling the type of advertisement and so on.

Use interceptor

After defining these conditions, you can use it, add as needed, and finally get an object processed by each interceptor. According to some values ​​in this object, proceed to the next step.

        //拦截过滤不需要跳转启动页的情况
        SplashAdStatusBean statusBean = new SplashAdStatusBean(true, 5, activity);
        SplashAdChain chain = new SplashAdChain()
                .addInterceptor(new SplashAdActivityInterceptor())
                .addInterceptor(new SplashAdChannelInterceptor())
                .addInterceptor(new SplashAdTimesInterceptor());
        chain.doProcess(statusBean);
        //拦截后如果需要跳转,那就跳转吧~~~
        if (statusBean.isNeedGoSplashAd()) {
            SPUtils.put(activity, "lastSplashTime", System.currentTimeMillis());
            SPUtils.put(activity, "todayOpenCount", (statusBean.getTodayOpenCount() + 1));
            Intent goSplash = new Intent(activity, SplashActivity.class);
            goSplash.putExtra("isFromOtherApp", true);
            activity.startActivity(goSplash);
        }

Conclusion

Such a division will significantly increase the number of classes, but we can see these filtering and intercepting operations more clearly, and we can make changes more clearly in the future, reducing code coupling.

Guess you like

Origin blog.csdn.net/lizebin_bin/article/details/98482096