在軟件構建過程中,考試大提示:某些對象的狀態(tài)如果改變,其行為也會隨之而發(fā)生變化,比如文檔處于只讀狀態(tài),其支持的行為和讀寫狀態(tài)支持的行為就可能完全不同,如何在運行時根據(jù)對象的狀態(tài)來透明的更改對象行為?而不會為對象操作和狀態(tài)轉化之間引入緊耦合?
意圖:
允許一個對象在其內部狀態(tài)改變時改變它的行為。從而使對象看起來似乎修改了其行為
public class Context
{
private State m_State;
public Context(State state)
{
m_State = state;
}
public void ChangeState(State state)
{
m_State = state;
}
public void Handle()
{
m_State.Operate(this);
}
}
public abstract class State
{
public abstract void Operate(Context ctx);
}
public class ConcreteStateA : State
{
public override void Operate(Context ctx)
{
Console.WriteLine("The State is processed By A");
ctx.ChangeState(new ConcreteStateB());
}
}
public class ConcreteStateB : State
{
public override void Operate(Context ctx)
{
Console.WriteLine("The State is processed By B");
ctx.ChangeState(new ConcreteStateA());
}
}
class Program
{
static void Main(string[] args)
{
State state = new ConcreteStateB();
Context ctx = new Context(state);
ctx.Handle();
ctx.Handle();
ctx.Handle();
ctx.Handle();
Console.Read();
}
}
從上面的代碼來看,我們抽象了一個狀態(tài)機的基類State,他有個一個抽象方法Operate,通過這個方法的參數(shù)來間接的調用上下文的引用。我們在ConcreteStateA和ConcreteStateB中實現(xiàn)了Operate方法,并且在執(zhí)行一段代碼之后自動切換到下一個狀態(tài),我們這里只存在兩種狀態(tài),所以他是互相切換的,我們可以添加多種狀態(tài),讓狀態(tài)一步步的切換。注意,狀態(tài)的切換不由Context來控制。在Context類中,我們保存了State的私有變量用來存儲當前Context的狀態(tài)。ChangeState方法我們讓新的狀態(tài)替換原有的狀態(tài)引用,相當于切換了狀態(tài)。Handle方法處理了客戶端的請求,并且State對象將操作自己對應的方法。我們通過多態(tài)的概念來自動調用對應的Operate方法。在Operate方法中,我們也可以不用傳Context引用,但是我們在狀態(tài)切換的時候,很有可能要改變Context其他的屬性或行為,所以這個地方傳遞Context引用。Context的Handle方法我們只是在這里做個演示進行互相切換,我們完全可以擴充其他的方法,先切換一個狀態(tài),再來調用狀態(tài)的Operate方法。當然State也可以擴充其他的方法,表明Context其他內容的變化
考試大提示要點:
State模式將所有與一個特定狀態(tài)相關的行為都放入一個State的子類對象中,在對象狀態(tài)切換時,切換響應的對象;但同時維持State的接口,這樣實現(xiàn)了具體操作與狀態(tài)轉換之間的解藕。
為不同的狀態(tài)引入不同的對象使得狀態(tài)轉換變得更加明確,而且可以保證不會出現(xiàn)狀態(tài)不一致的情況,因為轉換是原子性的--即要么徹底轉換過來,要么不轉換
如果State對象沒有實例變量,那么各個上下文可以共享同一個State對象,從而節(jié)省對象開銷。
這種模式避免了我們寫大量的if else或switch case語句,但是很有可能會導致某些系統(tǒng)有過多的具體狀態(tài)類,并且由此導致開發(fā)人員可能會對所有的狀態(tài)類有所遺漏。
意圖:
允許一個對象在其內部狀態(tài)改變時改變它的行為。從而使對象看起來似乎修改了其行為
public class Context
{
private State m_State;
public Context(State state)
{
m_State = state;
}
public void ChangeState(State state)
{
m_State = state;
}
public void Handle()
{
m_State.Operate(this);
}
}
public abstract class State
{
public abstract void Operate(Context ctx);
}
public class ConcreteStateA : State
{
public override void Operate(Context ctx)
{
Console.WriteLine("The State is processed By A");
ctx.ChangeState(new ConcreteStateB());
}
}
public class ConcreteStateB : State
{
public override void Operate(Context ctx)
{
Console.WriteLine("The State is processed By B");
ctx.ChangeState(new ConcreteStateA());
}
}
class Program
{
static void Main(string[] args)
{
State state = new ConcreteStateB();
Context ctx = new Context(state);
ctx.Handle();
ctx.Handle();
ctx.Handle();
ctx.Handle();
Console.Read();
}
}
從上面的代碼來看,我們抽象了一個狀態(tài)機的基類State,他有個一個抽象方法Operate,通過這個方法的參數(shù)來間接的調用上下文的引用。我們在ConcreteStateA和ConcreteStateB中實現(xiàn)了Operate方法,并且在執(zhí)行一段代碼之后自動切換到下一個狀態(tài),我們這里只存在兩種狀態(tài),所以他是互相切換的,我們可以添加多種狀態(tài),讓狀態(tài)一步步的切換。注意,狀態(tài)的切換不由Context來控制。在Context類中,我們保存了State的私有變量用來存儲當前Context的狀態(tài)。ChangeState方法我們讓新的狀態(tài)替換原有的狀態(tài)引用,相當于切換了狀態(tài)。Handle方法處理了客戶端的請求,并且State對象將操作自己對應的方法。我們通過多態(tài)的概念來自動調用對應的Operate方法。在Operate方法中,我們也可以不用傳Context引用,但是我們在狀態(tài)切換的時候,很有可能要改變Context其他的屬性或行為,所以這個地方傳遞Context引用。Context的Handle方法我們只是在這里做個演示進行互相切換,我們完全可以擴充其他的方法,先切換一個狀態(tài),再來調用狀態(tài)的Operate方法。當然State也可以擴充其他的方法,表明Context其他內容的變化
考試大提示要點:
State模式將所有與一個特定狀態(tài)相關的行為都放入一個State的子類對象中,在對象狀態(tài)切換時,切換響應的對象;但同時維持State的接口,這樣實現(xiàn)了具體操作與狀態(tài)轉換之間的解藕。
為不同的狀態(tài)引入不同的對象使得狀態(tài)轉換變得更加明確,而且可以保證不會出現(xiàn)狀態(tài)不一致的情況,因為轉換是原子性的--即要么徹底轉換過來,要么不轉換
如果State對象沒有實例變量,那么各個上下文可以共享同一個State對象,從而節(jié)省對象開銷。
這種模式避免了我們寫大量的if else或switch case語句,但是很有可能會導致某些系統(tǒng)有過多的具體狀態(tài)類,并且由此導致開發(fā)人員可能會對所有的狀態(tài)類有所遺漏。

