今天咱們講的是狀態模式【State Pattern】、這個名字咋一看很差理解,可是仔細一想仍是比較容易的。狀態模式重點關注的是狀態。狀態又牽扯着什麼呢?房屋的狀態暫且能夠分爲出租、簽定合同、退房。那麼出租對應的是什麼呢?出租狀態表明能夠租房。能夠租房是一個行爲了。因此不難理解的是狀態模式關注的是狀態的改變與行爲的變化。設計模式
在軟件系統中,常常狀態的改變影響着行爲的變化。例如房屋狀態是出租既能夠租房、出售既能夠買賣房、不租售意味不可操做。那麼如何避免對象操做和狀態轉換之間出現緊耦合呢?狀態模式將每種狀態對應的行爲抽象出來成爲單獨新的對象,這樣狀態的變化再也不依賴於對象內部的行爲正解決了此問題。bash
容許對象在內部狀態發生改變時改變它的行爲,對象看起來好像修改了它的類。ui
咱們看下案例圖中主要三個部分:this
環境角色:包含保留了一個具體狀態的實例、給出當前狀態及調用方法。spa
抽象狀態:定義接口、封裝一個狀態相對應的行爲方法。設計
具體狀態:實現具體狀態對應的的具體對應行爲。code
咱們繼續看這個房屋的案例,針對房屋咱們整理這麼一個案例,租房而後簽定合同。合同半年內退房無押金。租房時間達到半年退房可得押金。咱們看下代碼實現吧:cdn
namespace State_Pattern
{
/// <summary>
/// 房屋對象類
/// </summary>
public class StatePattern
{
/// <summary>
/// 房屋Id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 房屋名稱
/// </summary>
public string Name { get; set; }
/// <summary>
/// 租房時間/月
/// </summary>
public int Time { get; set; }
/// <summary>
/// 房屋狀態
/// </summary>
public HouseState State { get; set; }
/// <summary>
/// 是否退押金
/// </summary>
public bool IsDeposit { get; set; }
}
/// <summary>
/// 房屋出租狀態枚舉
/// </summary>
public enum HouseState
{
[Description("出租")]
Lease =1,
[Description("簽定合同")]
Leaseed = 2,
[Description("退房")]
Deposit = 3,
}
/// <summary>
/// 環境角色
/// </summary>
public class Environmental
{
public State _state;
/// <summary>
/// 初始化房屋狀態
/// </summary>
public Environmental()
{
this._state = new LeaseState();
}
public StatePattern _statePattern { get; set; }
/// <summary>
/// 獲取房屋對象
/// </summary>
/// <param name="statePattern"></param>
public void GetStatePattern(StatePattern statePattern,State state=null)
{
_statePattern = statePattern;
if (state!=null)
{
_state = state;
}
}
/// <summary>
/// 更改狀態方法
/// </summary>
/// <param name="state"></param>
public void SetState(State state)
{
_state = state;
}
public void Show()
{
if (this._statePattern!=null)
{
_state.Handle(this);
}
else
{
Console.WriteLine("無可操做房屋!");
}
}
}
/// <summary>
/// 抽象狀態接口
/// </summary>
public interface State
{
void Handle(Environmental environmental);
}
/// <summary>
/// 出租狀態
/// </summary>
public class LeaseState : State
{
public void Handle(Environmental environmental)
{
//房屋出租
if (environmental._statePattern.State==HouseState.Lease)
{
Console.WriteLine($"{environmental._statePattern.Name}房屋正在出租!");
Console.WriteLine("若是以爲能夠的話就簽定租房合同!");
environmental.SetState(new LeaseedState());
environmental.Show();
}
}
}
/// <summary>
/// 簽定合同狀態
/// </summary>
public class LeaseedState : State
{
public void Handle(Environmental environmental)
{
//後期辦理退房手續
if (environmental._statePattern.State == HouseState.Lease)
{
Console.WriteLine($"{environmental._statePattern.Name}簽定租房合同!");
environmental._statePattern.State = HouseState.Leaseed;
environmental._statePattern.Time = 1;
environmental.SetState(new DepositState());
environmental.Show();
}
}
}
/// <summary>
/// 退房有押金狀態
/// </summary>
public class DepositState : State
{
public void Handle(Environmental environmental)
{
environmental._statePattern.IsDeposit = true;
if (environmental._statePattern.State == HouseState.Leaseed && environmental._statePattern.Time < 6)
{
Console.WriteLine($"{environmental._statePattern.Name}若是如今退房的話是不能退押金的!");
environmental._statePattern.IsDeposit = false;
}
else
Console.WriteLine($"{environmental._statePattern.Name}若是如今退房的話是能夠退押金的!");
Console.WriteLine("考慮是否退房!");
}
}
}複製代碼
namespace State_Pattern
{
class Program
{
static void Main(string[] args)
{
//初始化房源信息
List<StatePattern> statePatterns = new List<StatePattern>();
statePatterns.Add(new StatePattern {Id=1,Name="房屋一",State=HouseState.Lease });
Environmental environmental = new Environmental();
//房屋一出租
environmental.GetStatePattern(statePatterns.Where(x=>x.Id==1).FirstOrDefault());
environmental.Show();
//時間大於半年可退押金
statePatterns[0].Time = 7;
environmental.Show();
}
}
}複製代碼
在上面的代碼運行以後房屋一的狀態在其對象內部發送了改變,從而行爲也發送了變化。剛開始的正在出租改變成了簽定合同出租以後。行爲變化也從簽定合同轉變成了退房操做。 對象
一、行爲隨着狀態改變而改變的場景。blog
二、條件或分支語句的替代者。
一、封裝了狀態及行爲的轉換規則。
二、在編寫錢枚舉出可能的狀態,肯定狀態的種類。
三、方便狀態的增長。只須要改變狀態便可改變對象的行爲。擴展性好。
四、能夠多個環境一塊兒共享一個狀態對象,減小了對象個數。
一、狀態模式會增長系統類和對象的個數
二、對開閉原則不友好。增長狀態須要對那些負責狀態轉換的代碼進行修改。不然的話沒法轉換到最新的狀態。
三、狀態模式的結構和實現都比較複雜,使用不當容易形成代碼混亂及難理解。
狀態模式到這裏介紹完了,狀態模式模式注重的狀態在內部的改變自動改變其行爲。對象看起來好像改變了它的類同樣。抓住重點實現。第一個是狀態的變化。第二個是狀態變化引發的行爲變化。第三個是在狀態內部改變的。把狀態的轉換邏輯和狀態對象放在一塊兒。繼而替換一個龐大的語句條件。
時間抓起來講是金子,抓不住就是流水。
歡迎你們掃描下方二維碼,和我一塊兒踏上設計模式的闖關之路吧!