5.8 STATE(狀態(tài)) — 對象行為型模式

1 意圖

允許一個其對象在其內部狀態(tài)改變時改變它的行為欧漱,對象看起來似乎修改了它的類。

2 別名

狀態(tài)對象(Objects For States)

3 動機

考慮一個表示網絡連接的類TCPConnection缀程。一個TCPConnection對象的狀態(tài)處于若干不同狀態(tài)之一:連接已建立(Established)、正在監(jiān)聽(Listening)、連接已關閉(Closed)形庭。當一個TCPConnection對象收到其他對象的請求時劫侧,它根據自身的當前狀態(tài)作出不同的反應埋酬。例如,一個Open請求的結果依賴于該連接是處于連接已關閉狀態(tài)還是連接已建立狀態(tài)烧栋。State模式描述了TCPConnection如何在每一種狀態(tài)下表現(xiàn)出不同的行為写妥。

這一模式的關鍵思想是引入了一個稱為TCPState的抽象類來表示網絡的連接狀態(tài)。TCPState類為各表示不同的操作狀態(tài)的子類聲明了一個公共接口审姓。TCPState的子類實現(xiàn)與特定狀態(tài)相關的行為珍特。例如,TCPEstablished和TCPClosed類分別實現(xiàn)了特定于TCPConnection的連接已建立狀態(tài)和連接已關閉狀態(tài)的行為邑跪。


image.png

TCPConnection類維護一個表示TCP連接當前狀態(tài)的狀態(tài)對象(一個TCPState子類的實例)次坡。TCPConnection類將所有與狀態(tài)相關的請求委托給這個狀態(tài)對象。TCPConnection使用它的TCPState子類實例來執(zhí)行特定于連接狀態(tài)的操作画畅。
一旦連接狀態(tài)改變砸琅,TCPConnection對象就會改變它所使用的狀態(tài)對象。例如當連接從已建立狀態(tài)轉為已關閉狀態(tài)時轴踱,TCPConnection會用一個TCPClosed的實例來代替原來的TCPEstablished的實例症脂。

4 適用性

在下面的兩種情況下均可使用State模式:

  • 一個對象的行為取決于它的狀態(tài),并且它必須在運行時刻根據狀態(tài)改變它的行為淫僻;
  • 一個操作中含有龐大的多分支的條件語句诱篷,且這些分支依賴于該對象的狀態(tài)。這個狀態(tài)通常用一個或多個枚舉常量表示雳灵。通常 , 有多個操作包含這一相同的條件結構棕所。state模式將每一個條件分支放入一個獨立的類中。這使得你可以根據對象自身的情況將對象的狀態(tài)作為一個對象悯辙,這一對象可以不依賴于其他對象而獨立變化琳省。
5 結構
image.png
6 參與者
  • Context(環(huán)境,如TCPConnection)
    ——定義客戶感興趣的接口
    ——維護一個ConcreteState子類的實例躲撰,這個實例定義當前的狀態(tài)
  • State(狀態(tài)针贬,如TCPState)
    ——定義一個接口以封裝與Context的一個特定狀態(tài)相關的行為
  • ConcreteState subclasses(具體狀態(tài)子類,如TCPEstablished拢蛋,TCPListen桦他,TCPClosed)
    ——每一子類實現(xiàn)一個與Context的一個狀態(tài)相關的行為
7 協(xié)作
  • Context將與狀態(tài)相關的請求委托給當前的ConcreteState對象處理;
  • Context可將自身作為一個參數傳遞給處理該請求的狀態(tài)對象谆棱。這使得狀態(tài)對象在必要時可訪問Context快压;
  • Context是客戶使用的主要接口圆仔。客戶可用狀態(tài)對象來配置一個Context嗓节,一旦一個Context配置完畢荧缘, 它的客戶不再需要直接與狀態(tài)對象打交道。
  • Context或ConcreteState子類都可決定哪個狀態(tài)是另外哪一個的后繼者拦宣,以及是在何種條件下進行條件轉換截粗。
8 效果

State模式有下面一些效果:

  • 1 它將與特定狀態(tài)相關的行為局部化,并且將不同狀態(tài)的行為分割開來
  • 2 它使得狀態(tài)轉換顯式化:當一個對象僅以內部數據值來定義當前狀態(tài)時 , 其狀態(tài)僅表現(xiàn)為對一些變量的賦值鸵隧,這不夠明確绸罗。為不同的狀態(tài)引入獨立的對象使得轉換變得更加明確。而且, State對象可保證Context不會發(fā)生內部狀態(tài)不一致的情況豆瘫,因為從Context的角度看珊蟀,狀態(tài)轉換是原子的 — 只需重新綁定一個變量,(即Context的State對象變量)外驱,而無需為多個變量賦值育灸。
  • 3 State對象可被共享:如果State對象沒有實例變量 — 即它們表示的狀態(tài)完全以它們的類型來編碼 — 那么各Context對象可以共享一個State對象。當狀態(tài)以這種方式被共享時 , 它們必然是沒有內部狀態(tài), 只有行為的輕量級對象昵宇。
9 實現(xiàn)

實現(xiàn)State模式有多方面的考慮:

  • 1 誰定義狀態(tài)轉換:State模式不指定哪一個參與者定義狀態(tài)轉換準則磅崭。如果該準則是固定的, 那么它們可在Context中完全實現(xiàn)。然而若讓State子類自身指定它們的后繼狀態(tài)以及何時進行轉換 , 通常更靈活更合適瓦哎。這需要Context增加一個接口 , 讓State對象顯式地設定Context的當前狀態(tài)砸喻。
    用這種方法分散轉換邏輯可以很容易地定義新的State子類來修改和擴展該邏輯。 這樣做的一個缺點是蒋譬,一個State子類至少擁有一個其他子類的信息 , 這就再各子類之間產生了實現(xiàn)依賴割岛。
  • 2 基于表的另一種方法:在C++ Programming Style中,Cargil描述了另一種將結構加載在狀態(tài)驅動的代碼上的方法 : 他使用表將輸入映射到狀態(tài)轉換犯助。對每一個狀態(tài) , 一張表將每一個可能的輸入映射到一個后繼狀態(tài)癣漆。實際上 , 這種方法將條件代碼 (和State模式下的虛函數)映射為一個查找表。
    表的主要好處是它們的規(guī)則性 : 你可以通過更改數據而不是更改程序代碼來改變狀態(tài)轉換的準則剂买。然而它也有一些缺點:
    • 對表的查找通常不如(虛)函數調用效率高扑媚;
    • 用統(tǒng)一的、表格的形式表示轉換邏輯使得轉換準則變得不夠明確而難以理解雷恃;
    • 通常難以加入伴隨狀態(tài)轉換的一些動作。表驅動的方法描述了狀態(tài)和它們之間的轉換费坊,但必須擴充這個機制以便在每一個轉換上能夠進行任意的計算倒槐。
      表驅動的狀態(tài)機和State模式的主要區(qū)別可以被總結如下: State模式對與狀態(tài)相關的行為進行建模, 而表驅動的方法著重于定義狀態(tài)轉換。
  • 3 創(chuàng)建和銷毀State對象:一個常見的值得考慮的實現(xiàn)上的權衡是 , 究竟是( 1 )僅當需要State對象時才創(chuàng)建它們并隨后銷毀它們附井,還是 ( 2 )提前創(chuàng)建它們并且始終不銷毀它們讨越。
    當將要進入的狀態(tài)在運行時是不可知的 , 并且上下文不經常改變狀態(tài)時 , 第一種選擇較為可取两残。這種方法避免創(chuàng)建不會被用到的對象 , 如果State對象存儲大量的信息時這一點很重要。當狀態(tài)改變很頻繁時, 第二種方法較好把跨。在這種情況下最好避免銷毀狀態(tài) , 因為可能很快再次需要用到它們人弓。此時可以預先一次付清創(chuàng)建各個狀態(tài)對象的開銷 , 并且在運行過程中根本不存在銷毀狀態(tài)對象的開銷。但是這種方法可能不太方便 , 因為Context必須保存對所有可能會進入的那些狀態(tài)的引用着逐。
  • 4 使用動態(tài)繼承:改變一個響應特定請求的行為可以用在運行時刻改變這個對象的類的辦法實現(xiàn), 但這在大多數面向對象程序設計語言中都是不可能的崔赌。 Self 和其他一些基于委托的語言卻是例外,它們提供這種機制 , 從而直接支持State模式耸别。Self 中的對象可將操作委托給其他對象以達到某種形式的動態(tài)繼承健芭。在運行時刻改變委托的目標有效地改變了繼承的結構。這一機制允許對象改變它們的行為秀姐,也就是改變它們的類慈迈。
10 代碼示例

github地址

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市省有,隨后出現(xiàn)的幾起案子痒留,更是在濱河造成了極大的恐慌,老刑警劉巖蠢沿,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伸头,死亡現(xiàn)場離奇詭異,居然都是意外死亡搏予,警方通過查閱死者的電腦和手機熊锭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雪侥,“玉大人碗殷,你說我怎么就攤上這事∷儆В” “怎么了锌妻?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長旬牲。 經常有香客問我仿粹,道長,這世上最難降的妖魔是什么原茅? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任吭历,我火速辦了婚禮,結果婚禮上擂橘,老公的妹妹穿的比我還像新娘晌区。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布朗若。 她就那樣靜靜地躺著恼五,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哭懈。 梳的紋絲不亂的頭發(fā)上灾馒,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機與錄音遣总,去河邊找鬼睬罗。 笑死,一個胖子當著我的面吹牛彤避,可吹牛的內容都是我干的傅物。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼琉预,長吁一口氣:“原來是場噩夢啊……” “哼董饰!你這毒婦竟也來了?” 一聲冷哼從身側響起圆米,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤卒暂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后娄帖,有當地人在樹林里發(fā)現(xiàn)了一具尸體也祠,經...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年近速,在試婚紗的時候發(fā)現(xiàn)自己被綠了诈嘿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡削葱,死狀恐怖奖亚,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情析砸,我是刑警寧澤昔字,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站首繁,受9級特大地震影響作郭,放射性物質發(fā)生泄漏。R本人自食惡果不足惜弦疮,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一夹攒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胁塞,春花似錦芹助、人聲如沸堂湖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至伺糠,卻和暖如春蒙谓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背训桶。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工累驮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人舵揭。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓谤专,卻偏偏與公主長得像,于是被迫代替她去往敵國和親午绳。 傳聞我的和親對象是個殘疾皇子置侍,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內容