狀態(tài)模式(State)

參考博客iOS App的設(shè)計(jì)模式開發(fā)中對(duì)State狀態(tài)模式的運(yùn)用

使用場(chǎng)景:

例子1:按鈕來(lái)控制一個(gè)電梯的狀態(tài)想幻,一個(gè)電梯開們恋谭,關(guān)門,停漓踢,運(yùn)行牵署。每一種狀態(tài)改變,都有可能要根據(jù)其他狀態(tài)來(lái)更新處理喧半。例如奴迅,開門狀體,你不能在運(yùn)行的時(shí)候開門挺据,而是在電梯定下后才能開門取具。

例子2:我們給一部手機(jī)打電話脖隶,就可能出現(xiàn)這幾種情況:用戶開機(jī),用戶關(guān)機(jī)者填,用戶欠費(fèi)停機(jī)浩村,用戶消戶等做葵。 所以當(dāng)我們撥打這個(gè)號(hào)碼的時(shí)候:系統(tǒng)就要判斷占哟,該用戶是否在開機(jī)且不忙狀態(tài),又或者是關(guān)機(jī)酿矢,欠費(fèi)等狀態(tài)榨乎。但不管是那種狀態(tài)我們都應(yīng)給出對(duì)應(yīng)的處理操作。

基本概念

狀態(tài)模式(State)瘫筐,當(dāng)一個(gè)對(duì)象的內(nèi)下狀態(tài)改變時(shí)蜜暑,允許改變其行為,這個(gè)對(duì)象看起來(lái)像是改變了其類策肝。

狀態(tài)模式主要解決的是當(dāng)控制一個(gè)對(duì)象狀態(tài)轉(zhuǎn)換的條件表達(dá)式過(guò)于復(fù)雜時(shí)的情況肛捍。把狀態(tài)的判斷邏輯轉(zhuǎn)移到表示不同狀態(tài)的一系列類當(dāng)中,可以把復(fù)雜的判斷邏輯簡(jiǎn)化之众。


環(huán)境類(Context):? 定義客戶感興趣的接口拙毫。維護(hù)一個(gè)ConcreteState子類的實(shí)例,這個(gè)實(shí)例定義當(dāng)前狀態(tài)棺禾。

抽象狀態(tài)類(State):? 定義一個(gè)接口以封裝與Context的一個(gè)特定狀態(tài)相關(guān)的行為缀蹄。

具體狀態(tài)類(ConcreteState):? 每一子類實(shí)現(xiàn)一個(gè)與Context的一個(gè)狀態(tài)相關(guān)的行為。

工作狀態(tài)-狀態(tài)模式版:



代碼實(shí)現(xiàn):

//抽象狀態(tài)

#import "Work.h"

@interface State : NSObject

- (void)writeProgramWithWork:(Work *)work;// 工作

@end

// 上午工作狀態(tài)

#import "ForenoonState.h"

#import "NoonState.h"

@implementation ForenoonState

- (void)writeProgramWithWork:(Work *)work

{

if (work.hour< 12) {

NSLog(@"當(dāng)前時(shí)間為%zd 上午工作 精神百倍",work.hour);

}else{

NoonState *state = [[NoonState alloc] init];

[state writeProgramWithWork:work];

}

}

//中午狀態(tài)

#import "NoonState.h"

#import "AfternoonState.h"

@implementation NoonState

- (void)writeProgramWithWork:(Work *)work

{

if (work.hour< 13) {

NSLog(@"當(dāng)前時(shí)間為%zd 餓了 困了 吃飯 午休",work.hour);

}else{

AfternoonState *state = [[AfternoonState alloc] init];

[state writeProgramWithWork:work];

}

}

// 下午狀態(tài)

#import "AfternoonState.h"

#import "EveningState.h"

@implementation AfternoonState

- (void)writeProgramWithWork:(Work *)work

{

if (work.hour< 17) {

NSLog(@"當(dāng)前時(shí)間為%zd 下午狀態(tài)還不錯(cuò)膘婶,繼續(xù)努力",work.hour);

}else{

EveningState *state = [[EveningState alloc] init];

[state writeProgramWithWork:work];

}

}

@end

// 晚上狀態(tài)

#import "EveningState.h"

#import "SleepingState.h"

#import "RestState.h"

@implementation EveningState

- (void)writeProgramWithWork:(Work *)work

{

if (work.finish) {// 如果任務(wù)完成就休息

RestState *state = [[RestState alloc] init];

[state writeProgramWithWork:work];

}else{

if (work.hour< 21) {

NSLog(@"當(dāng)前時(shí)間為%zd 生活不易需要加班",work.hour);

}else{

SleepingState *state = [[SleepingState alloc] init];

[state writeProgramWithWork:work];

}

}

}

@end

// 睡覺狀態(tài)

#import "SleepingState.h"

@implementation SleepingState

- (void)writeProgramWithWork:(Work *)work

{

NSLog(@"實(shí)在困的不行了缺前,要好好的休息");

}

@end

// 下班休息狀態(tài)

#import "RestState.h"

@implementation RestState

- (void)writeProgramWithWork:(Work *)work

{

NSLog(@"下班回家好好休息");

}

@end

// work類的實(shí)現(xiàn)

@class State;

@interface Work : NSObject

@property (nonatomic, strong)State *current;

@property (nonatomic, assign)int hour;

@property (nonatomic, assign)BOOL finish;

- (void)writeProgram;

@end

#import "Work.h"

#import "ForenoonState.h"

@implementation Work

- (instancetype)init

{

self = [super init];

if (self) {

self.current = [[ForenoonState alloc]init];

}

return self;

}

- (void)writeProgram

{

[self.current writeProgramWithWork:self];

}

@end

通過(guò)這個(gè)例子,可以看到悬襟,狀態(tài)模式通過(guò)把各種狀態(tài)轉(zhuǎn)移邏輯分布到State的子類之間衅码,來(lái)減少相互間的依賴。當(dāng)一個(gè)對(duì)象的行為取決于它的狀態(tài)脊岳,并且它必須在運(yùn)行時(shí)刻根據(jù)狀態(tài)改變它的行為時(shí)肆良,就可以考慮使用狀態(tài)模式了。

State模式有下面一些效果:

狀態(tài)模式的優(yōu)點(diǎn):

1 ) 它將與特定狀態(tài)相關(guān)的行為局部化逸绎,并且將不同狀態(tài)的行為分割開來(lái): State模式將所有與一個(gè)特定的狀態(tài)相關(guān)的行為都放入一個(gè)對(duì)象中惹恃。因?yàn)樗信c狀態(tài)相關(guān)的代碼都存在于某一個(gè)State子類中, 所以通過(guò)定義新的子類可以很容易的增加新的狀態(tài)和轉(zhuǎn)換。另一個(gè)方法是使用數(shù)據(jù)值定義內(nèi)部狀態(tài)并且讓 Context操作來(lái)顯式地檢查這些數(shù)據(jù)棺牧。但這樣將會(huì)使整個(gè)Context的實(shí)現(xiàn)中遍布看起來(lái)很相似的條件if else語(yǔ)句或switch case語(yǔ)句巫糙。增加一個(gè)新的狀態(tài)可能需要改變?nèi)舾蓚€(gè)操作, 這就使得維護(hù)變得復(fù)雜了。State模式避免了這個(gè)問(wèn)題, 但可能會(huì)引入另一個(gè)問(wèn)題, 因?yàn)樵撃J綄⒉煌瑺顟B(tài)的行為分布在多個(gè)State子類中颊乘。這就增加了子類的數(shù)目参淹,相對(duì)于單個(gè)類的實(shí)現(xiàn)來(lái)說(shuō)不夠緊湊醉锄。但是如果有許多狀態(tài)時(shí)這樣的分布實(shí)際上更好一些, 否則需要使用巨大的條件語(yǔ)句。正如很長(zhǎng)的過(guò)程一樣浙值,巨大的條件語(yǔ)句是不受歡迎的恳不。它們形成一大整塊并且使得代碼不夠清晰,這又使得它們難以修改和擴(kuò)展开呐。 State模式提供了一個(gè)更好的方法來(lái)組織與特定狀態(tài)相關(guān)的代碼烟勋。決定狀態(tài)轉(zhuǎn)移的邏輯不在單塊的 i f或s w i t c h語(yǔ)句中, 而是分布在State子類之間。將每一個(gè)狀態(tài)轉(zhuǎn)換和動(dòng)作封裝到一個(gè)類中筐付,就把著眼點(diǎn)從執(zhí)行狀態(tài)提高到整個(gè)對(duì)象的狀態(tài)卵惦。這將使代碼結(jié)構(gòu)化并使其意圖更加清晰。

2) 它使得狀態(tài)轉(zhuǎn)換顯式化: 當(dāng)一個(gè)對(duì)象僅以內(nèi)部數(shù)據(jù)值來(lái)定義當(dāng)前狀態(tài)時(shí) , 其狀態(tài)僅表現(xiàn)為對(duì)一些變量的賦值瓦戚,這不夠明確沮尿。為不同的狀態(tài)引入獨(dú)立的對(duì)象使得轉(zhuǎn)換變得更加明確。而且, State對(duì)象可保證Context不會(huì)發(fā)生內(nèi)部狀態(tài)不一致的情況较解,因?yàn)閺?Context的角度看畜疾,狀態(tài)轉(zhuǎn)換是原子的—只需重新綁定一個(gè)變量(即Context的State對(duì)象變量),而無(wú)需為多個(gè)變量賦值

3) State對(duì)象可被共享 如果State對(duì)象沒有實(shí)例變量—即它們表示的狀態(tài)完全以它們的類型來(lái)編碼—那么各Context對(duì)象可以共享一個(gè)State對(duì)象印衔。當(dāng)狀態(tài)以這種方式被共享時(shí), 它們必然是沒有內(nèi)部狀態(tài), 只有行為的輕量級(jí)對(duì)象啡捶。

狀態(tài)模式的缺點(diǎn):

1) 狀態(tài)模式的使用必然會(huì)增加系統(tǒng)類和對(duì)象的個(gè)數(shù)。

2) 狀態(tài)模式的結(jié)構(gòu)與實(shí)現(xiàn)都較為復(fù)雜当编,如果使用不當(dāng)將導(dǎo)致程序結(jié)構(gòu)和代碼的混亂届慈。

具體實(shí)踐聯(lián)想:

在公司中有一個(gè)流程是課程的報(bào)名那么他會(huì)有多種狀態(tài),例如結(jié)束忿偷,開始金顿,報(bào)名成功,報(bào)名成功和支付成功等鲤桥,針對(duì)這些不同的狀態(tài)具體的操作又不一樣揍拆,同時(shí)還有包含的關(guān)系,例如開始報(bào)名的話茶凳,就需要報(bào)名嫂拴,和支付兩個(gè)狀態(tài)同時(shí)出現(xiàn),這個(gè)剛好進(jìn)入的狀態(tài)是開始報(bào)名贮喧,當(dāng)報(bào)名成功后將狀態(tài)變?yōu)閳?bào)名成功筒狠,在調(diào)用報(bào)名成功狀態(tài)下的方法,這樣既可以將各個(gè)操作簡(jiǎn)單的寫一次箱沦,也可以將各個(gè)操作分開處理辩恼,利于代碼的梳理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市灶伊,隨后出現(xiàn)的幾起案子疆前,更是在濱河造成了極大的恐慌,老刑警劉巖聘萨,帶你破解...
    沈念sama閱讀 222,865評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竹椒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡米辐,警方通過(guò)查閱死者的電腦和手機(jī)胸完,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)儡循,“玉大人舶吗,你說(shuō)我怎么就攤上這事征冷≡裣ィ” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵检激,是天一觀的道長(zhǎng)肴捉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)叔收,這世上最難降的妖魔是什么齿穗? 我笑而不...
    開封第一講書人閱讀 60,199評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮饺律,結(jié)果婚禮上窃页,老公的妹妹穿的比我還像新娘。我一直安慰自己复濒,他們只是感情好脖卖,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著巧颈,像睡著了一般畦木。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上砸泛,一...
    開封第一講書人閱讀 52,793評(píng)論 1 314
  • 那天十籍,我揣著相機(jī)與錄音,去河邊找鬼唇礁。 笑死勾栗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盏筐。 我是一名探鬼主播围俘,決...
    沈念sama閱讀 41,221評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了楷拳?” 一聲冷哼從身側(cè)響起绣夺,我...
    開封第一講書人閱讀 40,174評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎欢揖,沒想到半個(gè)月后陶耍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,699評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡她混,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評(píng)論 3 343
  • 正文 我和宋清朗相戀三年烈钞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坤按。...
    茶點(diǎn)故事閱讀 40,918評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡毯欣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出臭脓,到底是詐尸還是另有隱情酗钞,我是刑警寧澤,帶...
    沈念sama閱讀 36,573評(píng)論 5 351
  • 正文 年R本政府宣布来累,位于F島的核電站砚作,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏嘹锁。R本人自食惡果不足惜葫录,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望领猾。 院中可真熱鬧米同,春花似錦、人聲如沸摔竿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拯坟。三九已至但金,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郁季,已是汗流浹背冷溃。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梦裂,地道東北人似枕。 一個(gè)月前我還...
    沈念sama閱讀 49,364評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像年柠,于是被迫代替她去往敵國(guó)和親凿歼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容