這篇文章給大家分享的是有關java設計模式之狀態模式的示例分析的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
定義
很多時候,一個對象的行為會根據一個動態的屬性變化而變化,這樣的一個對象我們可以稱為是有狀態的對象.
那么狀態模式就是允許一個對象在其內部狀態改變時候去改變對象的行為. 狀態模式的關鍵就是區分其對象內部動態變化狀態是什么.
現實世界舉例論證
一個電燈泡,有一個開關按鈕, 默認是關閉狀態,按一下切換到亮燈狀態,再按一下切換到關閉狀態,循環往復.
我們使用面向對象寫法實現上述的場景.
class Button {
constructor (light) {
this.light = light;
}
onPress () {
if (this.light.status === 'close') {
this.light.status = 'open';
console.log('開燈');
} else {
this.light.status = 'close';
console.log('關燈');
}
}
}
class Light {
constructor () {
this.status = 'close';
}
}
const light = new Light();
const button = new Button(light);
button.onPress();
button.onPress();
button.onPress();
但是現實場景中有些燈的狀態不只是開關,比如它還是只有一個開關,第一次按是開弱光,再按是開強光,再按才是關,依次循環.
此時我們的代碼如何按照下述方法擴展:
class Button {
constructor (light) {
this.light = light;
}
onPress () {
if (this.light.status === 'close') {
this.light.status = 'light';
console.log('開弱光燈');
} else if (this.light.status === 'light') {
this.light.status = 'strong';
console.log('開強光燈');
} else {
this.light.status = 'close';
console.log('關燈');
}
}
}
你會發下上述代碼的缺點:
違反SOLID中的O原則(對擴展開發,對修改關閉)。
每次增加一個燈的狀態,就要修該onPress方法,使得代碼非常不穩定,不利于維護.
過多的if else, 不利于代碼閱讀.
我們可以使用狀態模式對上述代碼進行重構.
找出狀態對象中的可變屬性,將其抽象為一個單獨的類,跟這個狀態有關的行為都封裝在其類里面.
class Button {
constructor (light) {
this.weakLightStatus = new WeakLightStatus(light);
this.strongLightStatus = new StrongLightStatus(light);
this.offLightStatus = new OffLightStatus(light);
}
onPress () {
this[light.status].onPress();
}
}
class Light {
constructor () {
this.status = 'offLightStatus';
}
// 切換狀態類
setStatus (statusClass) {
this.status = statusClass;
}
}
// 抽象類
class LightStatus {
constructor (light) {
this.light = light;
}
}
// 弱光
class WeakLightStatus extends LightStatus {
constructor (light) {
super(light);
}
onPress () {
this.light.setStatus('strongLightStatus');
console.log('開弱光燈');
}
}
// 強光
class StrongLightStatus extends LightStatus {
constructor (light) {
super(light);
}
onPress () {
this.light.setStatus('offLightStatus');
console.log('開強光燈');
}
}
// 關閉
class OffLightStatus extends LightStatus {
constructor (light) {
super(light);
}
onPress () {
this.light.setStatus('weakLightStatus');
console.log('關燈');
}
}
const light = new Light();
const button = new Button(light);
button.onPress();
button.onPress();
button.onPress();
button.onPress();
通過重構之后的代碼, 很明顯就是提供了代碼的可閱讀性, 可維護性.方便后續需求的擴展,雖然會增加一定的代碼量.
現在我們通過對GOF書中對狀態模式的定義來加深自己的總結:
允許一個對象在其內部狀態變化時候去改變它的行為, 對象似乎看起來改變了它的類
歸納分析:
把變化的屬性(狀態)封裝成不同的類, 并把請求委托給當前的對象狀態, 不同的狀態此時執行不同的行為
從使用者角度看, 我們使用的對象在不同狀態下有不同的行為, 彷佛這個對象是由不同類實例化而來, 這是因為請求委托的緣故.
模式結構
狀態模式包含如下角色:
Context: 環境類
State: 抽象狀態類
ConcreteState: 具體狀態類
類比之前我們上述的實例場景: Context指的就是Button類. State指的就是LightStatus. ConcreteState指的就是各個不同狀態的類.
狀態模式描述了對象狀態的變化以及對象如何在每一種狀態下表現出不同的行為。
狀態模式的關鍵是引入了一個抽象類來專門表示對象的狀態,這個類我們叫做抽象狀態類,而對象的每一種具體狀態類都繼承了該類,并在不同具體狀態類中實現了不同狀態的行為,包括各種狀態之間的轉換。
在狀態模式結構中需要理解環境類與抽象狀態類的作用:
環境類實際上就是擁有狀態的對象,環境類有時候可以充當狀態管理器(State Manager)的角色,可以在環境類中對狀態進行切換操作。
抽象狀態類可以是抽象類,也可以是接口,不同狀態類就是繼承這個父類的不同子類,狀態類的產生是由于環境類存在多個狀態,同時還滿足兩個條件: 這些狀態經常需要切換,在不同的狀態下對象的行為不同。因此可以將不同對象下的行為單獨提取出來封裝在具體的狀態類中,使得環境類對象在其內部狀態改變時可以改變它的行為,對象看起來似乎修改了它的類,而實際上是由于切換到不同的具體狀態類實現的。由于環境類可以設置為任一具體狀態類,因此它針對抽象狀態類進行編程,在程序運行時可以將任一具體狀態類的對象設置到環境類中,從而使得環境類可以改變內部狀態,并且改變行為。
狀態模式的優缺點
優點:
狀態模式定義的狀態-行為的對應關系, 并將其封裝在一個類里面, 我們只需要擴展具體狀態類就可以擴展需求.
避免了Context類的代碼無限膨脹和過多的條件分支判斷.
Context類中的請求于具體狀態類的行為隔離互補影響.
缺點:
如果狀態類很多, 需要不斷擴展代碼量.
狀態模式的結構與實現都較為復雜,如果使用不當將導致程序結構和代碼的混亂。
狀態模式對“開閉原則”的支持并不太好,對于可以切換狀態的狀態模式,增加新的狀態類需要修改那些負責狀態轉換的源代碼,否則無法切換到新增狀態;而且修改某個狀態類的行為也需修改對應類的源代碼。
狀態模式的性能優化點
管理State對像的創建與銷毀: 有兩種方式實現. 1. 僅僅當Satte對象需要的時候才去創建(節省內存).這個適合與那些State對象比較龐大的情景. 2. 一開始就創建所有的State對象,適用于State對象不多,以及狀態頻繁切換使用的情景.
我們上面的例子是一開始就創建了所有的State對象, 而且是為每一個Context類實例都創建了一組State對象,實際上我們這些State對象是可以在不同的Context類之間進行共享的(享元模式,后續再擴展說這一塊).
適用環境
對象的行為依賴于它的狀態(屬性)并且可以根據它的狀態改變而改變它的相關行為。
代碼中包含大量與對象狀態有關的條件語句,這些條件語句的出現,會導致代碼的可維護性和靈活性變差,不能方便地增加和刪除狀態,使客戶類與類庫之間的耦合增強。在這些條件語句中包含了對象的行為,而且這些條件對應于對象的各種狀態。
感謝各位的閱讀!關于“java設計模式之狀態模式的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。