狀態模式----State Pattern
阿新 • • 發佈:2018-11-15
當一個物件內在狀態改變時允許其改變行為,這個物件看起來像是改變了其類 。 Allow an object to alter its behavior when its internal state changes. The object will appear to change its class. [GoF, p305],也就是說狀態模式封裝的非常好,狀態的變更引起了行為的變更,從外部看起來就好像這個物件對應的類發生了改變一樣。
細想狀態變更的實質就是一個狀態與狀態二維的關係表。電梯例子,通過狀態的變化形成二維的表格,電梯門關閉、電梯門開啟、電梯上下運載、電梯停止。
如果通過一個個遍歷狀態通過if esle 完成程式碼不利於程式碼維護。
public abstract class LiftState { protected Context context; public void setContext(Context _context) { this.context = _context; } public abstract void open(); public abstract void close(); public abstract void run(); public abstract void stop(); }
public class Context { // 定義出所有的電梯狀態 public final static OpenningState openningState = new OpenningState(); public final static ClosingState closeingState = new ClosingState(); public final static RunningState runningState = new RunningState(); public final static StoppingState stoppingState = new StoppingState(); // 定一個當前電梯狀態 private LiftState liftState; public LiftState getLiftState() { return liftState; } public void setLiftState(LiftState liftState) { this.liftState = liftState; // 把當前的環境通知到各個實現類中 this.liftState.setContext(this); } public void open() { this.liftState.open(); } public void close() { this.liftState.close(); } public void run() { this.liftState.run(); } public void stop() { this.liftState.stop(); } }
public class ClosingState extends LiftState {
//電梯門關閉,這是關閉狀態要實現的動作
@Override
public void close() {
System.out.println("電梯門關閉...");
}
//電梯門關了再開啟,逗你玩呢,那這個允許呀
@Override
public void open() {
super.context.setLiftState(Context.openningState); //置為門敞狀態
super.context.getLiftState().open();
}
//電梯門關了就跑,這是再正常不過了
@Override
public void run() {
super.context.setLiftState(Context.runningState); //設定為執行狀態;
super.context.getLiftState().run();
}
//電梯門關著,我就不按樓層
@Override
public void stop() {
super.context.setLiftState(Context.stoppingState); //設定為停止狀態;
super.context.getLiftState().stop();
}
}
public class RunningState extends LiftState {
//電梯門關閉?這是肯定了
@Override
public void close() {
//do nothing
}
//執行的時候開電梯門?你瘋了!電梯不會給你開的
@Override
public void open() {
//do nothing
}
//這是在執行狀態下要實現的方法
@Override
public void run() {
System.out.println("電梯上下跑...");
}
//這個事絕對是合理的,光執行不停止還有誰敢做這個電梯?!估計只有上帝了
@Override
public void stop() {
super.context.setLiftState(Context.stoppingState); //環境設定為停止狀態;
super.context.getLiftState().stop();
}
}
public class StoppingState extends LiftState {
@Override
public void close() {
// do nothing;
}
@Override
public void open() {
super.context.setLiftState(Context.openningState);
super.context.getLiftState().open();
}
@Override
public void run() {
super.context.setLiftState(Context.runningState);
super.context.getLiftState().run();
}
@Override
public void stop() {
System.out.println("電梯停止了...");
}
}
public class Client {
public static void main(String[] args) {
Context context = new Context();
context.setLiftState(new ClosingState());
context.open();
context.close();
context.run();
context.stop();
}
}
優點:
首先是避免了過多的 swith…case或者if..else語句的使用,避免了程式的複雜性;
其次是很好的使用體現了開閉原則和單一職責原則,每個狀態都是一個子類,增加狀態就增加子類,你要修改狀態,你只修改一個子類就可以了;
最後一個好處就是封裝性非常好,這也是狀態模式的基本要求,狀態變換放置到了類的內部來實現,外部的呼叫不用知道類內部如何實現狀態和行為的變換。
缺點:子類會太多,也就是類膨脹。
工作流中 Activity(節點)有初始化狀態(Initialized State)、掛起狀態(Suspended State)、完成狀態(Completed State)等等,流程例項這麼多狀態,狀態怎麼管理呢?通過狀態機(State Machine)來管理, 狀態機就是 Context類的擴充套件版!