android项目重构之状态模式

闲来无事,继续对项目进行重构。这段时间在研究设计模式,苦于没有地方实战,不过现在机会来了。
这个项目是一个平台的商家版,所以会涉及到订单,其中有一个订单详情的页面。就是从网络拉取数据进行数据展示,还有做一些简单的接单之类的逻辑
但是如此简单的页面却写了将近700行代码。。。其中主要原因是因为订单的状态太多,这中间多了一系列的逻辑判断,每种订单都有不同的显示状态,都要进行处理
这让我一下就想到了状态模式,设计模式这东西,用语言很难表达清楚,直接上代码吧。

首先看看原来的代码,由于代码比较多,就抽取一部分

/**
     * 刷新页面ui,不同状态显示不同的页面效果
     *
     * @param type 订单类型
     */
    private void refreshUI(int type, int userCancelType) {
        Logger.e(TAG, "type:" + type);

        cb_user_assess.setChecked(payStatus==3);
        cb_user_assess.setDateVisiable(payStatus==3?View.VISIBLE: View.GONE);

        switch (type) {
            case Constants.INDENT_BOOK:
                ll_user_cancel.setVisibility(View.GONE);

                cb_had_receive.setChecked(false);
                cb_on_service.setChecked(false);
                cb_complete_service.setChecked(false);

                ll_refuse_receive.setVisibility(View.VISIBLE);
                break;
            case Constants.INDENT_RECEIVED:
                ll_user_cancel.setVisibility(View.GONE);

                tv_contact.setVisibility(View.VISIBLE);
                tv_contact.setText("联系客户");
                isCall = true;

                cb_had_receive.setChecked(true);
                cb_on_service.setChecked(false);
                cb_complete_service.setChecked(false);

                tv_contact.setVisibility(View.VISIBLE);
                tv_contact.setText(UIUtils.getString(R.string.contact_user));

                ll_refuse_receive.setVisibility(View.GONE);

                btn_receive.setVisibility(View.GONE);
                btn_refuse.setText("查看客户位置");
                btn_refuse.setBackgroundColor(UIUtils.getColor(R.color.update_location));
                btn_refuse.setTextColor(UIUtils.getColor(R.color.white));
                break;
            case Constants.INDENT_CANCEL:
                ll_user_cancel.setVisibility(View.VISIBLE);
                tv_not_need_service.setVisibility(View.VISIBLE);

                tv_contact.setVisibility(View.GONE);

                if (userCancelType == 1) {
                    cb_had_receive.setChecked(true);
                } else if (userCancelType == 2) {
                    cb_had_receive.setChecked(false);
                }

                cb_on_service.setChecked(false);
                cb_complete_service.setChecked(false);
                tv_business_refuse.setText("客户已取消订单");

                ll_refuse_receive.setVisibility(View.GONE);
                break;
            case Constants.INDENT_REFUSE:
                ll_user_cancel.setVisibility(View.VISIBLE);
                tv_not_need_service.setVisibility(View.GONE);
                cb_had_receive.setChecked(false);
                cb_on_service.setChecked(false);
                cb_complete_service.setChecked(false);

                tv_contact.setVisibility(View.GONE);
                tv_business_refuse.setText("拒绝接单");

                ll_refuse_receive.setVisibility(View.GONE);
                break;
            case Constants.INDENT_ONSERVICE:
                ll_user_cancel.setVisibility(View.GONE);
                cb_had_receive.setChecked(true);
                cb_on_service.setChecked(true);
                cb_complete_service.setChecked(false);

                tv_contact.setVisibility(View.VISIBLE);
                tv_contact.setText("完成服务");
                isCall = false;

                Logger.e(TAG, "服务中");

                ll_refuse_receive.setVisibility(View.GONE);

                break;
            case Constants.INDENT_COMPLETE:
                ll_user_cancel.setVisibility(View.GONE);
                cb_had_receive.setChecked(true);
                cb_on_service.setChecked(true);
                cb_complete_service.setChecked(true);

                tv_contact.setVisibility(View.VISIBLE);
                tv_contact.setText("联系客户");
                isCall = true;

                if(payStatus==0){
                    ll_refuse_receive.setVisibility(View.VISIBLE);
                } else {
                    ll_refuse_receive.setVisibility(View.GONE);
                }
                btn_receive.setVisibility(View.GONE);
                btn_refuse.setText("更改支付金额");
                btn_refuse.setBackgroundColor(UIUtils.getColor(R.color.price));
                btn_refuse.setTextColor(UIUtils.getColor(R.color.white));
                break;
            case Constants.INDENT_ASSESS:
                ll_user_cancel.setVisibility(View.GONE);
                cb_had_receive.setChecked(true);
                cb_on_service.setChecked(true);
                cb_complete_service.setChecked(true);

                tv_contact.setVisibility(View.VISIBLE);
                tv_contact.setText("联系客户");
                isCall = true;

                ll_refuse_receive.setVisibility(View.GONE);
                break;
        }
    }

7种订单状态,写了一长串的逻辑,这样的代码,光看着就好累,阅读性太差,下面不多说,开始重构
首先定义个订单状态的接口、里面包含四个抽象方法
public interface IIndentState {

    /**
     * 刷新订单状态的方法
     *
     * @param ll_cancel       取消订单的状态和原因
     * @param isv_had_receive 已接单
     * @param isv_on_service  服务中
     * @param isv_complete    已完成
     * @param isv_had_pay     已支付
     * @param ll_bottom       底部的按钮
     */
    void refreshUi(LinearLayout ll_cancel, IndentStateView isv_had_receive,
                   IndentStateView isv_on_service, IndentStateView isv_complete,
                   IndentStateView isv_had_pay, LinearLayout ll_bottom, TextView tv_title_right);

    /**
     * 底部左边按钮的点击逻辑
     */
    void onBottomLeftClick(long id, IndentDetailActivity activity, double lat, double lng, String user_phone, String order_id);

    /**
     * 底部右边的按钮的点击逻辑
     */
    void onBottomRightClick(IndentDetailContract.View view);

    /**
     * 标题右边的点击逻辑
     */
    void onTitleRightClick(String user_phone, IndentDetailActivity activity);
}



然后实现各种状态,首先定义个基类,实现一个重复的逻辑

public class BaseState implements IIndentState {

    private LinearLayout ll_cancel;
    private IndentStateView isv_had_receive;
    private IndentStateView isv_on_service;
    private IndentStateView isv_complete;
    private LinearLayout ll_bottom;
    protected TextView tv_not_need_service;
    protected TextView tv_business_refuse;
    protected Button btn_receive;
    protected Button btn_refuse;

    @Override
    public void refreshUi(LinearLayout ll_cancel, IndentStateView isv_had_receive,
                          IndentStateView isv_on_service, IndentStateView isv_complete,
                          IndentStateView isv_had_pay, LinearLayout ll_bottom,TextView tv_title_right) {
        this.ll_cancel = ll_cancel;
        this.isv_had_receive = isv_had_receive;
        this.isv_on_service = isv_on_service;
        this.isv_complete = isv_complete;
        this.ll_bottom = ll_bottom;

        tv_not_need_service = (TextView) ll_cancel.findViewById(R.id.tv_not_need_service);
        tv_business_refuse = (TextView) ll_cancel.findViewById(R.id.tv_business_refuse);
        btn_receive = (Button) ll_bottom.findViewById(R.id.btn_receive);
        btn_refuse = (Button) ll_bottom.findViewById(R.id.btn_refuse);
    }

    @Override
    public void onBottomLeftClick(long id, IndentDetailActivity activity, double lat, double lng, String user_phone, String order_id) {

    }

    @Override
    public void onBottomRightClick(IndentDetailContract.View view) {

    }

    @Override
    public void onTitleRightClick(String user_phone, IndentDetailActivity activity) {

    }

    /**
     * 设置订单的状态
     *
     * @param cancel_visibility 取消订单
     * @param had_receive       已接单
     * @param on_service        服务中
     * @param complete          服务完成
     * @param refuse_visibility 拒接
     */
    public void setStatus(int cancel_visibility, boolean had_receive,
                          boolean on_service, boolean complete, int refuse_visibility) {
        ll_cancel.setVisibility(cancel_visibility);
        isv_had_receive.setChecked(had_receive);
        isv_on_service.setChecked(on_service);
        isv_complete.setChecked(complete);
        ll_bottom.setVisibility(refuse_visibility);
    }
}


接下来的各种状态,只要去继承basestate,实现具体的逻辑就可以了,下面看预约的状态

public class BookState extends BaseState {

    @Override
    public void refreshUi(LinearLayout ll_cancel, IndentStateView isv_had_receive, IndentStateView isv_on_service, IndentStateView isv_complete, IndentStateView isv_had_pay, LinearLayout ll_bottom, TextView tv_title_right) {
        super.refreshUi(ll_cancel, isv_had_receive, isv_on_service, isv_complete, isv_had_pay, ll_bottom, tv_title_right);
        setStatus(View.GONE, false, false, false, View.VISIBLE);
    }

    @Override
    public void onBottomLeftClick(long id, IndentDetailActivity activity, double lat, double lng, String user_phone, String order_id) {
        super.onBottomLeftClick(id, activity, lat, lng, user_phone, order_id);
        // 拒接单的逻辑
        Intent intent = new Intent(activity, RefuseIndentActivity.class);
        intent.putExtra(Constants.INDENT_ID, id);
        activity.startActivityForResult(intent, 100);
    }

    @Override
    public void onBottomRightClick(IndentDetailContract.View view) {
        super.onBottomRightClick(view);
        // 接单的逻辑
        view.showReceiveDialog();
    }
}


以上是预约状态的具体实现、剩下还有待服务,服务中,待支付等状态。。。由于代码类似就不贴出来了,

每种状态都分离出一个类来去实现,就可以把activity里面的逻辑拆分开来

接着定义个indentcontext类,主要作用是作为设置状态的一个中介
public class IndentContext {

    private IIndentState mIndentState = new BookState();

    private static IndentContext mIndentContext;

    private IndentContext() {

    }

    /**
     * 获取IndentContext对象的方法
     *
     * @return IndentContext 对象
     */
    public static IndentContext getInstance() {
        if (mIndentContext == null) {
            synchronized (IndentContext.class) {
                if (mIndentContext == null) {
                    return mIndentContext = new IndentContext();
                }
            }
        }
        return mIndentContext;
    }

    /**
     * 设置状态
     *
     * @param state 订单的状态
     */
    public void setState(BaseState state) {
        mIndentState = state;
    }

    /**
     * 刷新订单状态的方法
     *
     * @param ll_cancel       取消订单的状态和原因
     * @param isv_had_receive 已接单
     * @param isv_on_service  服务中
     * @param isv_complete    已完成
     * @param isv_had_pay     已支付
     * @param ll_bottom       底部的按钮
     */
    public void refreshUI(LinearLayout ll_cancel, IndentStateView isv_had_receive,
                          IndentStateView isv_on_service, IndentStateView isv_complete,
                          IndentStateView isv_had_pay, LinearLayout ll_bottom, TextView tv_title_right) {
        mIndentState.refreshUi(ll_cancel, isv_had_receive, isv_on_service,
                isv_complete, isv_had_pay, ll_bottom, tv_title_right);
    }

    /**
     * 底部左边按钮的点击逻辑
     */
    public void onBottomLeftClick(long id, IndentDetailActivity activity, double lat, double lng, String user_phone, String order_id) {
        mIndentState.onBottomLeftClick(id, activity, lat, lng, user_phone, order_id);
    }

    /**
     * 底部右边的按钮的点击逻辑
     */
    public void onBottomRightClick(IndentDetailContract.View view) {
        mIndentState.onBottomRightClick(view);
    }

    /**
     * 标题右边的点击逻辑
     */
    public void onTitleRightClick(String user_phone, IndentDetailActivity activity) {
        mIndentState.onTitleRightClick(user_phone, activity);
    }
}


主要是调用state里的所有方法,同时可以更改状态,默认是预约状态
接着在订单详情的activity里面使用就可以了,上代码
先创建对象
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_indent_detail);
        indentContext = IndentContext.getInstance();
        initView();
        initEvent();
    }


接着,refreshui里面的逻辑就被简化成这样了

/**
     * 刷新页面ui,不同状态显示不同的页面效果
     *
     * @param type 订单类型
     */
    private void refreshUI(int type, int userCancelType) {
        Logger.e(TAG, "type:" + type);
        BaseState state = null;

        switch (type) {
            case Constants.INDENT_BOOK:
                state = new BookState();
                break;
            case Constants.INDENT_RECEIVED:
                state = new ReceivedState();
                break;
            case Constants.INDENT_CANCEL:
                if (userCancelType == 1) {
                    state = new UserCancelState();
                } else if (userCancelType == 2) {
                    state = new CancelBeforeReceivedState();
                }
                break;
            case Constants.INDENT_REFUSE:
                state = new BusinessRefuseState();
                break;
            case Constants.INDENT_ONSERVICE:
                state = new OnServiceState();
                break;
            case Constants.INDENT_COMPLETE:
            case Constants.INDENT_ASSESS:

                if (payStatus == 3) {
                    state = new HadPayState();
                } else {
                    state = new CompleteState();
                }
                break;
        }
        indentContext.setState(state);
        indentContext.refreshUI(ll_user_cancel, cb_had_receive, cb_on_service, cb_complete_service,
                cb_user_assess, ll_refuse_receive, tv_contact);
    }


然后是点击事件的逻辑,也不需要写那么多的if。。。else 了
 @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.tv_phone:
                // 打电话
                if (TextUtils.isEmpty(user_phone)) {
                    return;
                }

                toCallPhone(user_phone);
                break;
            case R.id.tv_contact:
                indentContext.onTitleRightClick(user_phone, this);
                break;
            case R.id.btn_receive:
                // 显示接单的对话框
                indentContext.onBottomRightClick(this);
                break;
            case R.id.btn_refuse:
                indentContext.onBottomLeftClick(id, this, lat, lng, user_phone, order_id);
                break;
            case R.id.iv_back:
                finish();
                break;
        }
    }

这样看起来就舒服了很多,而且维护起来也很简单,以后有什么状态需要修改的,直接去修改state类就行了,不需要动activity里面的代码。
当然设计模式少不了的就是弊端,这里很显然就是类的膨胀,一下子多了十几个类,不过为了让代码简洁,更容易维护,我觉得是值得的




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值