核心层的逻辑
核心层处于接口层和界面层之间,向下调用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之前处理。
核心层的逻辑就是这样了。最后就到界面层了。