定義(State Pattern):
當(dāng)一個(gè)對(duì)象內(nèi)在狀態(tài)改變時(shí)允許其改變行為,這個(gè)對(duì)象看起來(lái)像改變了其類股囊。
類圖:
啟示:
最近幾年寓辱,自動(dòng)駕駛被炒的是熱火朝天放航,國(guó)外的知名google语淘、uber妇汗、tesla惠拭,國(guó)內(nèi)的百度扩劝、樂視也都投入到了自動(dòng)駕駛的浪潮中去。像google和tesla的自動(dòng)駕駛技術(shù)已經(jīng)相對(duì)成熟职辅,可以上路了。比較火的純電動(dòng)支持自動(dòng)駕駛的特斯拉可謂是紅極一時(shí)聂示,官網(wǎng)號(hào)稱所有車型均搭載全自動(dòng)駕駛硬件域携。自動(dòng)駕駛作為一種發(fā)展趨勢(shì),相信在不久的將來(lái)鱼喉,我們每個(gè)人都能享受到這科技的紅利秀鞭。
說(shuō)到科技,我們就來(lái)簡(jiǎn)單探討下自動(dòng)駕駛涉及到的技術(shù)扛禽。首先锋边,這一切都需要必不可少的硬件支持,比如傳感器编曼、攝像頭豆巨、雷達(dá)。有了硬件就可以進(jìn)行數(shù)據(jù)采集掐场,收集駕駛過程中的各種信息往扔,通過算法進(jìn)行數(shù)據(jù)分析,來(lái)控制當(dāng)前的駕駛行為熊户。
換句話說(shuō)萍膛,自動(dòng)駕駛是結(jié)合外部因素和內(nèi)部因素通過算法分析來(lái)控制驅(qū)動(dòng)的。外部因素?zé)o外乎道路狀況嚷堡、交通標(biāo)志等蝗罗。內(nèi)部因素比如電池容量、車況等等蝌戒。
那這跟我們這節(jié)講的狀態(tài)模式有什么區(qū)別呢串塑?
在我理解,自動(dòng)駕駛也是狀態(tài)和行為相結(jié)合的瓶颠。
比如攝像頭檢測(cè)到路邊的限速標(biāo)記拟赊,自動(dòng)控制車速,比如攝像頭檢測(cè)到前方十字路口交通信號(hào)燈為紅燈粹淋,則停車等待吸祟。
其中限速標(biāo)記和交通燈都是一個(gè)狀態(tài)的體現(xiàn)瑟慈,控制車速和停車等待則是狀態(tài)驅(qū)動(dòng)的結(jié)果。但是呢屋匕,這些狀態(tài)行為并不符合我們狀態(tài)模式的定義(當(dāng)一個(gè)對(duì)象內(nèi)在狀態(tài)改變時(shí)允許其改變行為)葛碧。很顯然限速標(biāo)記和交通燈是外部狀態(tài)。
別失望过吻,我們來(lái)找找特斯拉的內(nèi)部狀態(tài)进泼。作為一輛車它的狀態(tài)其實(shí)很簡(jiǎn)單,也就是運(yùn)行纤虽、加速乳绕、減速、停車狀態(tài)逼纸。在停車狀態(tài)洋措,我們可以控制它啟動(dòng)運(yùn)行,切換至運(yùn)行狀態(tài)杰刽;在運(yùn)行狀態(tài)菠发,自動(dòng)駕駛根據(jù)行駛條件控制加速減速,切換至加速減速狀態(tài)贺嫂;到達(dá)目的地后滓鸠,泊車切換到停車狀態(tài)。
代碼:
這個(gè)應(yīng)用場(chǎng)景其實(shí)很簡(jiǎn)單第喳,按照我們傳統(tǒng)的寫法糜俗,我們肯定幾個(gè)if..else
或用switch..case
就搞定了。的確墩弯,但是呢吩跋,傳統(tǒng)的寫法就擴(kuò)展性和代碼結(jié)構(gòu)上就十分差強(qiáng)人意。廢話不多說(shuō)渔工,下面我們就以特斯拉自動(dòng)駕駛為例锌钮,分析下狀態(tài)模式的應(yīng)用。
首先我們定義一個(gè)狀態(tài)接口:
/// <summary>
/// 狀態(tài)接口類
/// </summary>
public interface ICarState
{
/// <summary>
/// 啟動(dòng)
/// </summary>
void Drive(Car car);
/// <summary>
/// 停車
/// </summary>
void Stop(Car car);
/// <summary>
/// 加速
/// </summary>
/// <param name="car"></param>
void SpeedUp(Car car);
/// <summary>
/// 減速
/// </summary>
/// <param name="car"></param>
void SpeedDown(Car car);
}
然后我們依次實(shí)現(xiàn)這四種狀態(tài)引矩。
運(yùn)行狀態(tài)下可以切換到其他三種狀態(tài)梁丘。
/// <summary>
/// 運(yùn)行狀態(tài)
/// </summary>
public class RuningState : ICarState
{
public void Drive(Car car)
{
Console.WriteLine("車輛正在自動(dòng)駕駛!");
}
public void Stop(Car car)
{
Console.WriteLine("車輛已停止旺韭!");
car.CurrentCarState = Car.StopState;
}
public void SpeedUp(Car car)
{
Console.WriteLine("路況良好氛谜,開始加速行駛!");
car.CurrentCarState = Car.SpeedUpState;
}
public void SpeedDown(Car car)
{
Console.WriteLine("路況一般区端,開始加速行駛值漫!");
car.CurrentCarState = Car.SpeedDownState;
}
}
停車狀態(tài)下,只能切換到啟動(dòng)狀態(tài)织盼,不可加速減速杨何。
/// <summary>
/// 停車狀態(tài)
/// </summary>
public class StopState : ICarState
{
public void Drive(Car car)
{
Console.WriteLine($"{car.Name}已啟動(dòng)酱塔,開始自動(dòng)駕駛!");
car.CurrentCarState = Car.RunState;
}
public void Stop(Car car)
{
Console.WriteLine("車輛已停止危虱!");
}
public void SpeedUp(Car car)
{
Console.WriteLine("車輛已停止羊娃!");
}
public void SpeedDown(Car car)
{
Console.WriteLine("車輛已停止!");
}
}
加速狀態(tài)也是運(yùn)行狀態(tài)埃跷,可減速或停車蕊玷。
/// <summary>
/// 加速狀態(tài)
/// </summary>
public class SpeedUpState : ICarState
{
public void Drive(Car car)
{
Console.WriteLine("車輛正在自動(dòng)駕駛!");
}
public void Stop(Car car)
{
Console.WriteLine("車輛已停止弥雹!");
car.CurrentCarState = Car.StopState;
}
public void SpeedUp(Car car)
{
Console.WriteLine("車輛正在加速行駛垃帅!");
}
public void SpeedDown(Car car)
{
Console.WriteLine("路況一般,減速行駛剪勿!");
car.CurrentCarState = Car.SpeedDownState;
}
}
減速狀態(tài)也是運(yùn)行狀態(tài)挺智,可加速或停車。
/// <summary>
/// 減速狀態(tài)
/// </summary>
public class SpeedDownState : ICarState
{
public void Drive(Car car)
{
Console.WriteLine("車輛正在自動(dòng)駕駛窗宦!");
}
public void Stop(Car car)
{
Console.WriteLine("車輛已停止!");
car.CurrentCarState = Car.StopState;
}
public void SpeedUp(Car car)
{
Console.WriteLine("路況良好二鳄,加速行駛赴涵!");
car.CurrentCarState = Car.SpeedUpState;
}
public void SpeedDown(Car car)
{
Console.WriteLine("車輛正在減速行駛!");
}
}
定義完?duì)顟B(tài)订讼,下面我們就來(lái)看看實(shí)際的車類髓窜。
public class Car
{
public string Name { get; set; }
public Car()
{
this.CurrentCarState = StopState;//初始狀態(tài)為停車狀態(tài)
}
internal static ICarState StopState = new StopState();
internal static ICarState RunState = new RuningState();
internal static ICarState SpeedDownState = new SpeedDownState();
internal static ICarState SpeedUpState = new SpeedUpState();
public ICarState CurrentCarState { get; set; }
public void Run()
{
this.CurrentCarState.Drive(this);
}
public void Stop()
{
this.CurrentCarState.Stop(this);
}
public void SpeedUp()
{
this.CurrentCarState.SpeedUp(this);
}
public void SpeedDown()
{
this.CurrentCarState.SpeedDown(this);
}
}
Car類也比較簡(jiǎn)單,主要是預(yù)先申明并實(shí)例化了幾種狀態(tài)并暴露設(shè)置當(dāng)前狀態(tài)的屬性欺殿,以及提供了狀態(tài)對(duì)應(yīng)的行為方法寄纵,并委托給具體的狀態(tài)去執(zhí)行相應(yīng)的動(dòng)作。
下面就是簡(jiǎn)單的場(chǎng)景類了脖苏。
static void Main(string[] args)
{
Car tesla = new Car() {Name = "特斯拉 Model S"};
tesla.Run();
tesla.SpeedUp();
tesla.SpeedDown();
tesla.Stop();
Console.WriteLine();
}
總結(jié):
狀態(tài)模式隱藏了具體的狀態(tài)變化程拭,但行為還是由狀態(tài)變化驅(qū)動(dòng)的。
就狀態(tài)模式而言棍潘,其實(shí)就僅僅三個(gè)角色:
- State——抽象狀態(tài)角色:接口或抽象類恃鞋,負(fù)責(zé)定義對(duì)象的所有狀態(tài)對(duì)應(yīng)的行為由具體狀態(tài)去實(shí)現(xiàn)。這里對(duì)應(yīng)的是我們定義的
ICarState
亦歉。 - ConcreteState——具體狀態(tài)角色:處理當(dāng)前狀態(tài)的行為恤浪,決定是否可以過渡到其他狀態(tài)。這里對(duì)應(yīng)的是我們定義的
RunState
肴楷、StopState
顷扩、SepeedUpState
昏鹃、SepeedDownState
。 - Context——環(huán)境角色:定義行為偿乖,狀態(tài)轉(zhuǎn)換。這里對(duì)應(yīng)的就是我們的
Car
類邑狸。
優(yōu)缺點(diǎn):
優(yōu)點(diǎn):結(jié)構(gòu)清晰;符合OCP和SRP;封裝性好圾结。
缺點(diǎn) :在狀態(tài)過多的情況下,會(huì)導(dǎo)致具體狀態(tài)類的膨脹齿诉。
應(yīng)用場(chǎng)景:
- 行為隨狀態(tài)改變而改變筝野。
- 狀態(tài)已確定,且狀態(tài)不宜過多粤剧。
- 重構(gòu)
if..else
或switch..case
的不二之選歇竟。