前言
狀態模式簡而言之就是指我要做一件事,這件事能導致什麼後果我不管,由當前狀態來決定,比如我有兩塊錢,我想吃點東西就去了商店,結果怎麼樣得看這個商店有兩塊錢的什麼東西,如果商品都大於兩塊,我還不能吃到食物了;這就和策略模式特別像了,他們的結構完全一樣,狀態模式的行爲是由狀態來決定,行爲是平行的不可替換的,而策略模式的行爲是可替換的,因爲它都是爲了完成同一個行爲。
適用情況
1,一個對象的行爲取決於它的狀態,而且程序執行中必須改變其行爲。
2,程序中有很多同一執行入口的if-else語句。
類與角色
Context: 定義統一執行入口,維護行爲的具體實例,或者說就是一個狀態行爲管理器。
State: 抽象狀態接口,定義抽象行爲接口。
ConcreteState: 抽象接口具體實現類,多個狀態對應多個接口實現類,滿足不同的行爲。
Demo
寫一個Demo,描述一個購物車頁面的場景,用戶可以刪除商品和結算商品,但是刪除和結算的行爲和用戶是否登錄有關係,如果沒有登錄就去登錄,如果已經登錄了,那就執行相關操作。
定義抽象狀態接口State,抽象刪除商品和結算方法:
package com.demo.state;
import android.content.Context;
/**
* Created by italkbb on 2017/12/18.
*/
public interface UserState {
/**
* 刪除商品
*/
void delShop(Context context);
/**
* 結算
*/
void settlement(Context context);
}
實現具體狀態接口:
package com.demo.state;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/**
* Created by italkbb on 2017/12/18.
*/
public class LoginedState implements UserState {
public final static String CLASSNAME = LoginedState.class.getSimpleName();
@Override
public void delShop(Context context) {
Log.e(CLASSNAME,"刪除購物車商品");
}
@Override
public void settlement(Context context) {
// 登錄了直接去支付頁面
Intent intent = new Intent(context,PayActivity.class);
context.startActivity(intent);
}
}
package com.demo.state;
import android.content.Context;
import android.content.Intent;
/**
* Created by italkbb on 2017/12/18.
*/
public class LogoutState implements UserState {
@Override
public void delShop(Context context) {
Intent intent = new Intent(context,LoginActivity.class);
context.startActivity(intent);
}
@Override
public void settlement(Context context) {
Intent intent = new Intent(context,LoginActivity.class);
context.startActivity(intent);
}
}
定義一個UserManager管理類,統一調用接口:
package com.demo.state;
import android.content.Context;
/**
* Created by italkbb on 2017/12/18.
*/
public class UserManager {
// 默認未登錄
private UserState mState = new LogoutState();
private static UserManager mUserManager = new UserManager();
private UserManager(){
}
/**
* 對外公佈獲取管理類接口
* @return
*/
public static UserManager getUserManager(){
return mUserManager;
}
public void setState(UserState userState){
this.mState = userState;
}
/**
* 統一刪除接口
* @param context
*/
public void delShop(Context context){
mState.delShop(context);
}
/**
* 統一結算接口
* @param context
*/
public void settlement(Context context){
mState.settlement(context);
}
}
簡單示例一下使用:
package com.demo.state;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import teltplay.example.com.kotlindemo.R;
public class CartActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
// // 在登錄成功後
// UserManager.getUserManager().setState(new LoginedState());
// // 在登出後
// UserManager.getUserManager().setState(new LogoutState());
findViewById(R.id.btn_cart).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
UserManager.getUserManager().settlement(CartActivity.this);
}
});
findViewById(R.id.btn_del).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
UserManager.getUserManager().settlement(CartActivity.this);
}
});
}
}
後記
最後簡單的說一下狀態模式的優缺點,優點是減少了if-else判斷,讓結構很清晰,而且調用的時候不用去管行爲結果,只需要調用統一管理類提供的公用方法。這樣避免了代碼的冗餘,也同樣提高了代碼的可擴展性和可維護性;缺點還是如策略模式,狀態越多類的數量就會增加,但這一般情況下又算什麼缺點呢。