設(shè)計模式系列—狀態(tài)模式
模式定義
對有狀態(tài)的對象,把復雜的“判斷邏輯”提取到不同的狀態(tài)對象中,允許狀態(tài)對象在其內(nèi)部狀態(tài)發(fā)生改變時改變其行為。
狀態(tài)模式把受環(huán)境改變的對象行為包裝在不同的狀態(tài)對象里,其意圖是讓一個對象在其內(nèi)部狀態(tài)改變的時候,其行為也隨之改變?,F(xiàn)在我們來分析其基本結(jié)構(gòu)和實現(xiàn)方法。
模板實現(xiàn)如下:
- package com.niuh.designpattern.state.v1;
 - /**
 - * <p>
 - * 狀態(tài)模式
 - * </p>
 - */
 - public class StatePattern {
 - public static void main(String[] args) {
 - //創(chuàng)建環(huán)境
 - Context context = new Context();
 - //處理請求
 - context.Handle();
 - context.Handle();
 - context.Handle();
 - context.Handle();
 - }
 - }
 - //抽象狀態(tài)類
 - abstract class State {
 - public abstract void Handle(Context context);
 - }
 - //具體狀態(tài)A類
 - class ConcreteStateA extends State {
 - public void Handle(Context context) {
 - System.out.println("當前狀態(tài)是 A.");
 - context.setState(new ConcreteStateB());
 - }
 - }
 - //具體狀態(tài)B類
 - class ConcreteStateB extends State {
 - public void Handle(Context context) {
 - System.out.println("當前狀態(tài)是 B.");
 - context.setState(new ConcreteStateA());
 - }
 - }
 - //環(huán)境類
 - class Context {
 - private State state;
 - //定義環(huán)境類的初始狀態(tài)
 - public Context() {
 - this.state = new ConcreteStateA();
 - }
 - //設(shè)置新狀態(tài)
 - public void setState(State state) {
 - this.state = state;
 - }
 - //讀取狀態(tài)
 - public State getState() {
 - return (state);
 - }
 - //對請求做處理
 - public void Handle() {
 - state.Handle(this);
 - }
 - }
 
輸出結(jié)果如下:
- 當前狀態(tài)是 A.
 - 當前狀態(tài)是 B.
 - 當前狀態(tài)是 A.
 - 當前狀態(tài)是 B.
 
解決的問題
對象的行為依賴于它的狀態(tài)(屬性),并且可以根據(jù)它的狀態(tài)改變而改變它的相關(guān)行為。
模式組成
實例說明
實例概況
用“狀態(tài)模式”設(shè)計一個多線程的狀態(tài)轉(zhuǎn)換程序。
分析:多線程存在 5 種狀態(tài),分別為新建狀態(tài)、就緒狀態(tài)、運行狀態(tài)、阻塞狀態(tài)和死亡狀態(tài),各個狀態(tài)當遇到相關(guān)方法調(diào)用或事件觸發(fā)時會轉(zhuǎn)換到其他狀態(tài),其狀態(tài)轉(zhuǎn)換規(guī)律如下所示:
現(xiàn)在先定義一個抽象狀態(tài)類(TheadState),然后為上圖的每個狀態(tài)設(shè)計一個具體狀態(tài)類,它們是新建狀態(tài)(New)、就緒狀態(tài)(Runnable )、運行狀態(tài)(Running)、阻塞狀態(tài)(Blocked)和死亡狀態(tài)(Dead),每個狀態(tài)中有觸發(fā)它們轉(zhuǎn)變狀態(tài)的方法,環(huán)境類(ThreadContext)中先生成一個初始狀態(tài)(New),并提供相關(guān)觸發(fā)方法,下圖所示是線程狀態(tài)轉(zhuǎn)換程序的結(jié)構(gòu)圖:
使用步驟
步驟1:定義抽象狀態(tài)類:線程狀態(tài)
- abstract class ThreadState {
 - //狀態(tài)名
 - protected String stateName;
 - }
 
步驟2: 定義具體的狀態(tài)類
- //具體狀態(tài)類:新建狀態(tài)
 - class New extends ThreadState {
 - public New() {
 - stateName = "新建狀態(tài)";
 - System.out.println("當前線程處于:新建狀態(tài).");
 - }
 - public void start(ThreadContext hj) {
 - System.out.print("調(diào)用start()方法-->");
 - if (stateName.equals("新建狀態(tài)")) {
 - hj.setState(new Runnable());
 - } else {
 - System.out.println("當前線程不是新建狀態(tài),不能調(diào)用start()方法.");
 - }
 - }
 - }
 - //具體狀態(tài)類:就緒狀態(tài)
 - class Runnable extends ThreadState {
 - public Runnable() {
 - stateName = "就緒狀態(tài)";
 - System.out.println("當前線程處于:就緒狀態(tài).");
 - }
 - public void getCPU(ThreadContext hj) {
 - System.out.print("獲得CPU時間-->");
 - if (stateName.equals("就緒狀態(tài)")) {
 - hj.setState(new Running());
 - } else {
 - System.out.println("當前線程不是就緒狀態(tài),不能獲取CPU.");
 - }
 - }
 - }
 - //具體狀態(tài)類:運行狀態(tài)
 - class Running extends ThreadState {
 - public Running() {
 - stateName = "運行狀態(tài)";
 - System.out.println("當前線程處于:運行狀態(tài).");
 - }
 - public void suspend(ThreadContext hj) {
 - System.out.print("調(diào)用suspend()方法-->");
 - if (stateName.equals("運行狀態(tài)")) {
 - hj.setState(new Blocked());
 - } else {
 - System.out.println("當前線程不是運行狀態(tài),不能調(diào)用suspend()方法.");
 - }
 - }
 - public void stop(ThreadContext hj) {
 - System.out.print("調(diào)用stop()方法-->");
 - if (stateName.equals("運行狀態(tài)")) {
 - hj.setState(new Dead());
 - } else {
 - System.out.println("當前線程不是運行狀態(tài),不能調(diào)用stop()方法.");
 - }
 - }
 - }
 - //具體狀態(tài)類:阻塞狀態(tài)
 - class Blocked extends ThreadState {
 - public Blocked() {
 - stateName = "阻塞狀態(tài)";
 - System.out.println("當前線程處于:阻塞狀態(tài).");
 - }
 - public void resume(ThreadContext hj) {
 - System.out.print("調(diào)用resume()方法-->");
 - if (stateName.equals("阻塞狀態(tài)")) {
 - hj.setState(new Runnable());
 - } else {
 - System.out.println("當前線程不是阻塞狀態(tài),不能調(diào)用resume()方法.");
 - }
 - }
 - }
 - //具體狀態(tài)類:死亡狀態(tài)
 - class Dead extends ThreadState {
 - public Dead() {
 - stateName = "死亡狀態(tài)";
 - System.out.println("當前線程處于:死亡狀態(tài).");
 - }
 - }
 
步驟3:定義環(huán)境類
- class ThreadContext {
 - private ThreadState state;
 - ThreadContext() {
 - state = new New();
 - }
 - public void setState(ThreadState state) {
 - this.state = state;
 - }
 - public ThreadState getState() {
 - return state;
 - }
 - public void start() {
 - ((New) state).start(this);
 - }
 - public void getCPU() {
 - ((Runnable) state).getCPU(this);
 - }
 - public void suspend() {
 - ((Running) state).suspend(this);
 - }
 - public void stop() {
 - ((Running) state).stop(this);
 - }
 - public void resume() {
 - ((Blocked) state).resume(this);
 - }
 - }
 
輸出結(jié)果
- 當前線程處于:新建狀態(tài).
 - 調(diào)用start()方法-->當前線程處于:就緒狀態(tài).
 - 獲得CPU時間-->當前線程處于:運行狀態(tài).
 - 調(diào)用suspend()方法-->當前線程處于:阻塞狀態(tài).
 - 調(diào)用resume()方法-->當前線程處于:就緒狀態(tài).
 - 獲得CPU時間-->當前線程處于:運行狀態(tài).
 - 調(diào)用stop()方法-->當前線程處于:死亡狀態(tài).
 
優(yōu)點
- 狀態(tài)模式將與特定狀態(tài)相關(guān)的行為局部化到一個狀態(tài)中,并且將不同狀態(tài)的行為分割開來,滿足“單一職責原則”。
 - 減少對象間的相互依賴。將不同的狀態(tài)引入獨立的對象中會使得狀態(tài)轉(zhuǎn)換變得更加明確,且減少對象間的相互依賴。
 - 有利于程序的擴展。通過定義新的子類很容易地增加新的狀態(tài)和轉(zhuǎn)換。
 
缺點
- 狀態(tài)模式的使用必然會增加系統(tǒng)的類與對象的個數(shù)。
 - 狀態(tài)模式的結(jié)構(gòu)與實現(xiàn)都較為復雜,如果使用不當會導致程序結(jié)構(gòu)和代碼的混亂。
 
應(yīng)用場景
通常在以下情況下可以考慮使用狀態(tài)模式。
- 當一個對象的行為取決于它的狀態(tài),并且它必須在運行時根據(jù)狀態(tài)改變它的行為時,就可以考慮使用狀態(tài)模式。
 - 一個操作中含有龐大的分支結(jié)構(gòu),并且這些分支決定于對象的狀態(tài)時。
 
狀態(tài)模式的擴展
在有些情況下,可能有多個環(huán)境對象需要共享一組狀態(tài),這時需要引入享元模式,將這些具體狀態(tài)對象放在集合中供程序共享,其結(jié)構(gòu)圖如下:
分析:共享狀態(tài)模式的不同之處是在環(huán)境類中增加了一個 HashMap 來保存相關(guān)狀態(tài),當需要某種狀態(tài)時可以從中獲取,其程序代碼如下:
- package com.niuh.designpattern.state.v3;
 - import java.util.HashMap;
 - /**
 - * <p>
 - * 共享狀態(tài)模式
 - * </p>
 - */
 - public class FlyweightStatePattern {
 - public static void main(String[] args) {
 - //創(chuàng)建環(huán)境
 - ShareContext context = new ShareContext();
 - //處理請求
 - context.Handle();
 - context.Handle();
 - context.Handle();
 - context.Handle();
 - }
 - }
 - //抽象狀態(tài)類
 - abstract class ShareState {
 - public abstract void Handle(ShareContext context);
 - }
 - //具體狀態(tài)1類
 - class ConcreteState1 extends ShareState {
 - public void Handle(ShareContext context) {
 - System.out.println("當前狀態(tài)是: 狀態(tài)1");
 - context.setState(context.getState("2"));
 - }
 - }
 - //具體狀態(tài)2類
 - class ConcreteState2 extends ShareState {
 - public void Handle(ShareContext context) {
 - System.out.println("當前狀態(tài)是: 狀態(tài)2");
 - context.setState(context.getState("1"));
 - }
 - }
 - //環(huán)境類
 - class ShareContext {
 - private ShareState state;
 - private HashMap<String, ShareState> stateSet = new HashMap<String, ShareState>();
 - public ShareContext() {
 - state = new ConcreteState1();
 - stateSet.put("1", state);
 - state = new ConcreteState2();
 - stateSet.put("2", state);
 - state = getState("1");
 - }
 - //設(shè)置新狀態(tài)
 - public void setState(ShareState state) {
 - this.state = state;
 - }
 - //讀取狀態(tài)
 - public ShareState getState(String key) {
 - ShareState s = (ShareState) stateSet.get(key);
 - return s;
 - }
 - //對請求做處理
 - public void Handle() {
 - state.Handle(this);
 - }
 - }
 
輸出結(jié)果如下
- 當前狀態(tài)是: 狀態(tài)1
 - 當前狀態(tài)是: 狀態(tài)2
 - 當前狀態(tài)是: 狀態(tài)1
 - 當前狀態(tài)是: 狀態(tài)2
 
源碼中的應(yīng)用
- #JDK中的狀態(tài)模式:
 - java.util.Iterator
 - # 通過FacesServlet控制, 行為取決于當前JSF生命周期的階段(狀態(tài)
 - javax.faces.lifecycle.LifeCycle#execute()
 
PS:以上代碼提交在 Github :
https://github.com/Niuh-Study/niuh-designpatterns.git




















 
 
 











 
 
 
 