用状态模式+建造者模式处理订单状态,删掉恶心的if/else

  • 《设计模式之禅》(第2版)第25章
    这个状态是如何产生的,以及这个状态怎样过渡到其他状态。
    State-抽象状态角色(接口或者抽象类 负责对象状态的定义,并且封装环境角色以实现状态切换)

ConcreteState-具体状态角色(本状态的行为管理和趋势状态处理)

Context-环境角色(定义客户端接口,并且负责具体状态的切换)

环境角色有两个不成文的约束

  • 把状态对象声明为静态常量,有几个状态对象就声明介个静态常量(至于为什么要声明为静态常量,我有点不理解)
  • 环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式
public class Client {
    public static void main(String[] args) {
        Context context=new Context();
        context.setCurrentState(new ConcreteState1());
        context.handle1();
        context.handle2();
    }
}
public class Context {
    public static final State STATE1 = new ConcreteState1();
    public static final State STATE2 = new ConcreteState2();

    private State currentState;

    public void setCurrentState(State state1) {
        currentState = state1;
        currentState.setContext(this);
    }

    //行为委托
    public void handle1() {
        this.currentState.handle1();
    }

    public void handle2() {
        this.currentState.handle2();
    }
}

public abstract class State {
    //定义一个环境角色 提供子类访问
    protected Context context;
    public Context getContext() {
        return context;
    }

    public State setContext(Context context) {
        this.context = context;
        return this;
    }

    //行为1
    protected abstract void handle1();
    //行为2
    protected abstract void handle2();

}
public class ConcreteState1 extends State {
    @Override
    protected void handle1() {
        //本状态下要处理的逻辑
    }

    @Override
    protected void handle2() {
        //设置当前状态state2
        super.context.setCurrentState(Context.STATE2);
        //过渡到状态2
        super.context.handle2();
    }
}
public class ConcreteState2 extends State {
    @Override
    protected void handle1() {

        //设置当前状态state1
        super.context.setCurrentState(Context.STATE1);
        //过渡到状态1
        super.context.handle1();
    }

    @Override
    protected void handle2() {
        //本状态下要处理的逻辑
    }
}

以上是基本的通用逻辑和流程,接下来我们来看看处理订单常有的功能

  • ”待付款“,”待发货“,”待收货“,”退款/售后“ 分为5个Tab时状态的处理
  • ”待付款“,”待发货“,”待收货“,”退款/售后“ 在同个RecycleView的处理
  • 订单列表Item的状态处理

解决方案

  • 结合状态模式和建造者模式

处理视图–建造者模式(Builder模式) 示例代码如下

    public static class Builder {
        private StateVisibility stateVisibility;
        private boolean evaluateVisible;
        private boolean askAgainVisible;
        private boolean reConsultVisible;
        private boolean deleteOrderVisible;
        private boolean modifyMsgVisible;
        private boolean reminderVisible;

        public Builder() {
            stateVisibility = new StateVisibility();
        }

        public Builder setEvaluateVisible(boolean evaluateVisible) {
            this.evaluateVisible = evaluateVisible;
            return this;
        }

        public Builder setAskAgainVisible(boolean askAgainVisible) {
            this.askAgainVisible = askAgainVisible;
            return this;
        }

        public Builder setReConsultVisible(boolean reConsultVisible) {
            this.reConsultVisible = reConsultVisible;
            return this;
        }

        public Builder setDeleteOrderVisible(boolean deleteOrderVisible) {
            this.deleteOrderVisible=deleteOrderVisible;
            return this;
        }

        public Builder setModifyMsgVisible(boolean modifyMsgVisible) {
            this.modifyMsgVisible=modifyMsgVisible;
            return this;
        }

        public Builder setReminderVisible(boolean reminderVisible) {
            this.reminderVisible=reminderVisible;
            return this;
        }

        private void build() {
            stateVisibility.reminderVisible = reminderVisible;
            stateVisibility.modifyMsgVisible = modifyMsgVisible;
            stateVisibility.deleteOrderVisible = deleteOrderVisible;
            stateVisibility.evaluateVisible = evaluateVisible;
            stateVisibility.askAgainVisible = askAgainVisible;
            stateVisibility.reConsultVisible = reConsultVisible;
        }


        private class StateVisibility {
            boolean evaluateVisible;
            boolean askAgainVisible;
            boolean reConsultVisible;
            boolean deleteOrderVisible;
            boolean modifyMsgVisible;
            boolean reminderVisible;
        }
    }

动作类的流程适合状态模式,比如点击了确认收货,会根据当前的订单状态允许或者不允许一些操作,比如,没有物流状态的包裹不允许确认收货,只允许查看物流,以及点击确认收货设置下一步的状态为已收货或者退货中之类的。需要修改下一步状态的才比较适合状态模式

   OrderContext orderContext = new OrderContext();
        orderContext.setCurrentState(context, itemModel, mQuestionTypeEnum);
        State.Builder builder = orderContext.getBuilder();

        holder.vRemindAnswer.setVisibility(builder.isReminderVisible());
        holder.vConsult.setVisibility(builder.isReConsultVisible());
        holder.vComment.setVisibility(builder.isEvaluateVisible());
        holder.vGoAskAgain.setVisibility(builder.isAskAgainVisible());
        holder.vOrderGuoqi.setVisibility(builder.isYiguoqiTipVisible());
        holder.vAnswerLayout.setVisibility(builder.isHasAnswer());
        holder.vTvModify.setVisibility(builder.isModifyMsgVisible());
        holder.vOrderMore.setVisibility(builder.isHasAnswer());
public class OrderContext {
//我这里就没声明是静态常量了
    public  State waitAnswerState = new WaitAnswerState();
    public  State answeredState = new AnsweredState();
    public  State overTimeState = new OverTimeState();
    public  State rejectedState = new RejectedState();
    private State currentState;
    private QuestionListModel.ListModel model;
    private Context context;
    private QuestionTypeEnum questionTypeEnum;

    public Context getContext() {
        return context;
    }

    public QuestionListModel.ListModel getModel() {
        return model;
    }

    public QuestionTypeEnum getQuestionTypeEnum() {
        return questionTypeEnum;
    }

    public void setCurrentState(Context context, QuestionListModel.ListModel model, QuestionTypeEnum questionTypeEnum) {
        this.model = model;
        this.context = context;
        this.questionTypeEnum = questionTypeEnum;
        State state = null;
        //0已提问,1已回答,2已过期 3已拒单
        switch (model.getStatus()) {
            case 0:
                state = waitAnswerState;
                break;
            case 1:
                state = answeredState;
                break;
            case 2:
                state = overTimeState;
                break;
            case 3:
                state = rejectedState;
                break;
        }
        setCurrentState(state);
    }

    private void setCurrentState(State state) {
        currentState = state;
        currentState.setmOrderContext(this);
    }

    public State.Builder getBuilder() {
        return this.currentState.getBuilder();
    }
}

public abstract class State {
    //定义一个环境角色 提供子类访问
    protected OrderContext mOrderContext;

    public State setmOrderContext(OrderContext mOrderContext) {
        this.mOrderContext = mOrderContext;
        return this;
    }

    @NonNull
    public abstract Builder getBuilder();
    }
public class AnsweredState extends State {

    @Override
    public Builder getBuilder() {
        QuestionListModel.ListModel itemModel = mOrderContext.getModel();

        CharSequence answerState = getAnswerState(itemModel);
        return new State.Builder()
                .setHasAnswer(true)
                .setAnswerState(answerState)
                .setAskAgainVisible(showAskAgain(itemModel))
                .setEvaluateVisible(!itemModel.getIsEvaluate())
                .setReConsultVisible(itemModel.getIsEvaluate())
                .build();
    }

    private CharSequence getAnswerState(QuestionListModel.ListModel itemModel) {
    //一些判断获取显示字段
   			... 
   }
}
public class WaitAnswerState extends State {

    @Override
    public Builder getBuilder() {
        return new State.Builder()
                .setReminderVisible(true)
                .setModifyMsgVisible(true)
                .setAnswerState(mOrderContext.getContext().getResources().getString(R.string.answer_ask_question_status_wait_answer))
                .build();
    }
}

当然你也可以直接用静态方法直接根据类型返回Builder,如果没有太多逻辑的话

你可能感兴趣的:(设计模式)