关于设计模式的文章,后续依次会更新,这里先放个彩蛋。
学习设计模式,一定要有自己的想法并在项目运用起来才能体验到它强大的好处,不然都是自嗨,俺第一次使用这个模式的时候是在做手游的时候,当时在军团战的时候,会出现多达7个状态,并且是依次连续出现,不能跳过。这些是题外话了,下面正式分析这个模式。
状态模式和适用的场景
- 类中定义了很多条件判断语句来进行不同的切换,并且下一个状态的切换是由上一个状态触发的
- 不想把具体的状态实现细节,数据结构暴露给调用者。
- 方便新增新的状态,也即方便扩展
这种说法好似放之四海而皆准,太过朦胧,有点雾里看花。下面使用一个网上下单的例子进行说明。下单的流程图如下:
在操作订单的时候,有一个很明显的特性,就是订单的状态不能随机跳跃,如果从“商品下单之后” 直接跳到 发货状态,那你老板,肯定会杀了你这个程序员来祭天。。。。。
状态模式角色分析
- 具体的状态类,这个可以上面这个流程图可以看出,在程序的角度,可以把各个状态抽象为一个类,这个类就用来处理这个状态所有的业务
- 为了使得具体的状态类乱来(乱定义函数接口),需要一个小组长来规范它的 行为(当然具体的行为,这个小组长无权过问,你只要在它规定的范围内干活,就没事 )接口规范类,暂且给它命名为:BaseOrderState
- 有了小组长之后,还需要一个调度员,它的角色就是告诉小组长,什么时候用什么状态,小组长收到通知之后就需要拿出具体的状态来应对,暂且将这个调度员命名为:StateContext
具体的代码实现
调度员类—状态管理类
public class StateContext {
private BaseOrderState state;
public void setState(BaseOrderState state){
this.state = state;
}
public void nextState(){
this.state.nextState(this);
}
public void preState(){
this.state.preState(this);
}
public String getCurState(){
String curState = this.state.getCurState();
System.out.println("27--------------State:"+curState);
return this.state.getCurState();
}
}
小组长类—具体状态函数接口约束类
/**
* Created by liuxiaobing on 13/07/2018.
* 所有订单的 基类,订单类,均需要扩展此类
* 订单状态为:预订---》 付款---》 核对--》 发货
*/
public abstract class BaseOrderState {
private StateContext context;
public abstract void nextState(StateContext context);
public abstract void preState(StateContext context);
public abstract String getCurState();
}
具体状态类—预订状态
public class BookingState extends BaseOrderState {
private static BookingState mState;
public static BookingState getInstance(){
if(mState == null){
mState = new BookingState();
}
return mState;
}
/*预订状态下一个状态 付款状态*/
@Override
public void nextState(StateContext context) {
context.setState(PayState.getInstance());
}
@Override
public void preState(StateContext context) {
System.out.println("-----回到了订单的初始状态了,没有上一个状态");
}
@Override
public String getCurState() {
return BookingState.class.getName();
}
}
具体状态类—付款状态
public class PayState extends BaseOrderState {
private static PayState mState;
public static PayState getInstance(){
if(mState == null){
mState = new PayState();
}
return mState;
}
@Override
public void nextState(StateContext context) {
context.setState(CheckState.getInstance());
}
@Override
public void preState(StateContext context) {
context.setState(BookingState.getInstance());
}
@Override
public String getCurState() {
return PayState.class.getName();
}
}
具体状态类—核对状态
public class CheckState extends BaseOrderState{
private static CheckState mState;
public static CheckState getInstance(){
if(mState == null){
mState = new CheckState();
}
return mState;
}
@Override
public void nextState(StateContext context) {
context.setState(DeliveryState.getInstance());
}
@Override
public void preState(StateContext context) {
context.setState(PayState.getInstance());
}
@Override
public String getCurState() {
return CheckState.class.getName();
}
}
具体状态类—发货状态
public class DeliveryState extends BaseOrderState {
private static DeliveryState mState;
public static DeliveryState getInstance(){
if(mState == null){
mState = new DeliveryState();
}
return mState;
}
public DeliveryState(){
try {
throw new Exception("请走单例获取实例模式");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void nextState(StateContext context) {
System.out.println("29----------订单流程快要走完了,没有下一个状态");
}
@Override
public void preState(StateContext context) {
context.setState(CheckState.getInstance());
}
@Override
public String getCurState() {
return DeliveryState.this.getClass().getName();
}
}
测试类:
package com.example.liuxiaobing.statemodel;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import com.example.liuxiaobing.statemodel.state_model2.BookingState;
import com.example.liuxiaobing.statemodel.state_model2.StateContext;
import com.example.liuxiaobing.statemodel.statemodel.BlackState;
import com.example.liuxiaobing.statemodel.statemodel.Context;
public class MainActivity extends AppCompatActivity {
private StateContext mStateMgr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView(){
mStateMgr = new StateContext();
mStateMgr.setState(BookingState.getInstance());
findViewById(R.id.next_state).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mStateMgr.nextState();
}
});
findViewById(R.id.pre_state).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mStateMgr.preState();
}
});
findViewById(R.id.cur_state).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mStateMgr.getCurState();
}
});
}
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.liuxiaobing.statemodel.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<Button
android:id="@+id/next_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="next_state"/>
<Button
android:id="@+id/pre_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="pre_state"/>
<Button
android:id="@+id/cur_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="cur_state"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
测试ui: