专栏首页Keegan小钢Android项目重构之路:实现篇(二)

Android项目重构之路:实现篇(二)

核心层的逻辑

核心层处于接口层和界面层之间,向下调用Api,向上提供Action,它的核心任务就是处理复杂的业务逻辑。先看看我对Action的定义:

public interface AppAction {
    // 发送手机验证码
    public void sendSmsCode(String phoneNum, ActionCallbackListener<Void> listener);
    // 注册
    public void register(String phoneNum, String code, String password, ActionCallbackListener<Void> listener);
    // 登录
    public void login(String loginName, String password, ActionCallbackListener<Void> listener);
    // 按分页获取券列表
    public void listCoupon(int currentPage, ActionCallbackListener<List<CouponBO>> listener);
}

首先,和Api接口对比就会发现,参数并不一致。登录并没有iemi和loginOS的参数,获取券列表的参数里也少了pageSize。这是因为,这几个参数,跟界面其实并没有直接关系。Action只要定义好跟界面相关的就可以了,其他需要的参数,在具体实现时再去获取。 另外,大部分action的处理都是异步的,因此,添加了回调监听器ActionCallbackListener,回调监听器的泛型则是返回的对象数据类型,例如获取券列表,返回的数据类型就是List,没有对象数据时则为Void。回调监听器只定义了成功和失败的方法,如下:

public interface ActionCallbackListener<T> {
    /**
     * 成功时调用
     *
     * @param data 返回的数据
     */
    public void onSuccess(T data);
    
    /**
     * 失败时调用
     *
     * @param errorEvemt 错误码
     * @param message    错误信息
     */
    public void onFailure(String errorEvent, String message);
}

接下来再看看Action的实现。首先,要获取imei,那就需要传入一个Context;另外,还需要loginOS和pageSize,这定义为常量就可以了;还有,要调用接口层,所以还需要Api实例。而接口的实现分为两步,第一步做参数检查,第二步用异步任务调用Api。具体实现如下:

public class AppActionImpl implements AppAction {
    private final static int LOGIN_OS = 1; // 表示Android
    private final static int PAGE_SIZE = 20; // 默认每页20条

    private Context context;
    private Api api;
    
    public AppActionImpl(Context context) {
        this.context = context;
        this.api = new ApiImpl();
    }
        
    @Override
    public void sendSmsCode(final String phoneNum, final ActionCallbackListener<Void> listener) {
        // 参数为空检查
        if (TextUtils.isEmpty(phoneNum)) {
            if (listener != null) {
                listener.onFailure(ErrorEvent.PARAM_NULL, "手机号为空");
            }
            return;
        }
        // 参数合法性检查
        Pattern pattern = Pattern.compile("1\\d{10}");
        Matcher matcher = pattern.matcher(phoneNum);
        if (!matcher.matches()) {
            if (listener != null) {
                listener.onFailure(ErrorEvent.PARAM_ILLEGAL, "手机号不正确");
            }
            return;
        }
            
        // 请求Api
        new AsyncTask<Void, Void, ApiResponse<Void>>() {
            @Override
            protected ApiResponse<Void> doInBackground(Void... voids) {
                return api.sendSmsCode4Register(phoneNum);
            }
                
            @Override
            protected void onPostExecute(ApiResponse<Void> response) {
                if (listener != null && response != null) {
                    if (response.isSuccess()) {
                        listener.onSuccess(null);
                    } else {
                        listener.onFailure(response.getEvent(), response.getMsg());
                    }
                }
            }
        }.execute();
    }
                    
    @Override
    public void register(final String phoneNum, final String code, final String password, final ActionCallbackListener<Void> listener) {
        // 参数为空检查
        if (TextUtils.isEmpty(phoneNum)) {
            if (listener != null) {
                listener.onFailure(ErrorEvent.PARAM_NULL, "手机号为空");
            }
            return;
        }
        if (TextUtils.isEmpty(code)) {
            if (listener != null) {
                listener.onFailure(ErrorEvent.PARAM_NULL, "验证码为空");
            }
            return;
        }
        if (TextUtils.isEmpty(password)) {
            if (listener != null) {
                listener.onFailure(ErrorEvent.PARAM_NULL, "密码为空");
            }
            return;
        }
            
        // 参数合法性检查
        Pattern pattern = Pattern.compile("1\\d{10}");
        Matcher matcher = pattern.matcher(phoneNum);
        if (!matcher.matches()) {
            if (listener != null) {
                listener.onFailure(ErrorEvent.PARAM_ILLEGAL, "手机号不正确");
            }
            return;
        }
        
        // TODO 长度检查,密码有效性检查等

        // 请求Api
        new AsyncTask<Void, Void, ApiResponse<Void>>() {
            @Override
            protected ApiResponse<Void> doInBackground(Void... voids) {
                return api.registerByPhone(phoneNum, code, password);
            }
                
            @Override
            protected void onPostExecute(ApiResponse<Void> response) {
                if (listener != null && response != null) {
                    if (response.isSuccess()) {
                        listener.onSuccess(null);
                    } else {
                        listener.onFailure(response.getEvent(), response.getMsg());
                    }
                }
            }
        }.execute();
    }
                    
    @Override
    public void login(final String loginName, final String password, final ActionCallbackListener<Void> listener) {
        // 参数为空检查
        if (TextUtils.isEmpty(loginName)) {
            if (listener != null) {
                listener.onFailure(ErrorEvent.PARAM_NULL, "登录名为空");
            }
            return;
        }
        if (TextUtils.isEmpty(password)) {
            if (listener != null) {
                listener.onFailure(ErrorEvent.PARAM_NULL, "密码为空");
            }
            return;
        }
            
        // TODO 长度检查,密码有效性检查等

        // 请求Api
        new AsyncTask<Void, Void, ApiResponse<Void>>() {
            @Override
            protected ApiResponse<Void> doInBackground(Void... voids) {
                TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
                String imei = telephonyManager.getDeviceId();
                return api.loginByApp(loginName, password, imei, LOGIN_OS);
            }
                
            @Override
            protected void onPostExecute(ApiResponse<Void> response) {
                if (listener != null && response != null) {
                    if (response.isSuccess()) {
                        listener.onSuccess(null);
                    } else {
                        listener.onFailure(response.getEvent(), response.getMsg());
                    }
                }
            }
        }.execute();
    }
    
    @Override
    public void listCoupon(final int currentPage, final ActionCallbackListener<List<CouponBO>> listener) {
        // 参数检查
        if (currentPage < 0) {
            if (listener != null) {
                listener.onFailure(ErrorEvent.PARAM_ILLEGAL, "当前页数小于零");
            }
        }
        
        // TODO 添加缓存

        // 请求Api
        new AsyncTask<Void, Void, ApiResponse<List<CouponBO>>>() {
            @Override
            protected ApiResponse<List<CouponBO>> doInBackground(Void... voids) {
                return api.listNewCoupon(currentPage, PAGE_SIZE);
            }
                
            @Override
            protected void onPostExecute(ApiResponse<List<CouponBO>> response) {
                if (listener != null && response != null) {
                    if (response.isSuccess()) {
                        listener.onSuccess(response.getObjList());
                    } else {
                        listener.onFailure(response.getEvent(), response.getMsg());
                    }
                }
            }
        }.execute();
    }
}

简单的实现代码就是这样,其实,这还有很多地方可以优化,比如,将参数为空的检查、手机号有效性的检查、数字型范围的检查等等,都可以抽成独立的方法,从而减少重复代码的编写。异步任务里的代码也一样,都是可以通过重构优化的。另外,需要扩展时,比如添加缓存,那就在调用Api之前处理。 核心层的逻辑就是这样了。最后就到界面层了。

本文分享自微信公众号 - Keegan小钢(keeganlee_me),作者:Keegan小钢

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2016-02-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • App项目实战之路(五):服务端篇

    近一个月因为忙于其他事情,一直没能抽出时间来更新项目进度。现在,只能趁着国庆期间,赶紧抽空更新下进度。这次,我想简单谈谈服务端的一些东西。

    Keegan小钢
  • Android样式的开发:Property Animation篇

    前篇文章说过,Android框架还提供了两种动画体系,前一篇已经总结了视图动画(View Animation)的用法,本篇则接着总结另一种动画体系——属性动画(...

    Keegan小钢
  • Android样式的开发:shape篇

    一个应用,应该保持一套统一的样式,包括Button、EditText、ProgressBar、Toast、Checkbox等各种控件的样式,还包括控件间隔、文字...

    Keegan小钢
  • 深入理解OkHttp源码(二)——获取响应

    在上一篇博客深入理解OkHttp源码(一)——提交请求中介绍到了getResponseWithInterceptorChain()方法,本篇主要从这儿继续往下...

    用户1108631
  • android中实现手机号码的校验的示例代码

    砸漏
  • Github开源项目贡献指南:创建一个开源项目

    当一个项目开源后,意味着不论什么目的,所有人都可以浏览,使用,修改和分发你的项目。 这些权限都是来自于开源协议, 开源非常的强大。因为它降低了使用的门槛,使新奇...

    腾讯开源
  • Java工具集-数学(数字工具类)

    cwl_java
  • 聊聊hystrix的queueSizeRejectionThreshold参数

    本文主要研究一下hystrix的queueSizeRejectionThreshold参数

    codecraft
  • 使用OkHttpClient处理json请求处理的方式

    一枝花算不算浪漫
  • 简单直白教你理解Java中四大引用强引用,软引用,弱引用,虚引用

    我属于自学型的,所以知识不够系统,只能是一边儿工作一边查漏补缺,在此要对那些写技术文章的人由衷的说句谢谢,谢谢各位大神们的分享 ? ONE,强引用(Strong...

    fanfan

扫码关注云+社区

领取腾讯云代金券