一個菜鳥的設計模式之旅,文章可能會有不對的地方,懇請大佬指出錯誤,
編程旅途是漫長遙遠的,在不同時刻有不同的感悟,本文會一直更新下去,
程式介紹

本程式實作狀態模式,一個玩家從滿血到死亡的程序有多個狀態,假定健康、輕傷、重傷、死亡狀態,當玩家扣血時判斷并切換狀態,觸發不同狀態的行為,
健康狀態 HP 90
健康狀態->輕傷狀態
輕傷狀態 HP 70
輕傷狀態->重傷狀態
重傷狀態 HP 50
重傷狀態 HP 30
重傷狀態 HP 10
重傷狀態->死亡狀態
玩家已死亡
強制玩家復活
健康狀態->輕傷狀態
輕傷狀態->重傷狀態
重傷狀態->死亡狀態
玩家已死亡
強制玩家復活
程式代碼
statePattern.go
package main
type ICharacter interface {
DecreaseHP(hp float64)
Respawn()
}
type Player struct {
*Life
}
func (p *Player) DecreaseHP(hp float64) {
p.Life.HP -= hp
p.Life.Request()
}
func (p *Player) Respawn() {
p.Life.HP = 100
p.Life.Request()
}
type ILifeState interface {
Handle(c *Life)
}
type Life struct {
state ILifeState
HP float64
}
func (c *Life) SetState(state ILifeState) {
c.state = state
}
func (c *Life) Request() {
c.state.Handle(c)
}
lifeStates.go
package main
import "fmt"
type HighHP struct{}
type MiddleHP struct{}
type LowHP struct{}
type ZeroHP struct{}
func (hp HighHP) Handle(Life *Life) {
if Life.HP > 80 {
fmt.Println("健康狀態 HP", Life.HP)
} else {
fmt.Println("健康狀態->輕傷狀態")
Life.SetState(&MiddleHP{})
Life.Request()
}
}
func (hp MiddleHP) Handle(Life *Life) {
if Life.HP > 50 {
fmt.Println("輕傷狀態 HP", Life.HP)
} else {
fmt.Println("輕傷狀態->重傷狀態")
Life.SetState(&LowHP{})
Life.Request()
}
}
func (hp LowHP) Handle(Life *Life) {
if Life.HP > 0 {
fmt.Println("重傷狀態 HP", Life.HP)
} else {
fmt.Println("重傷狀態->死亡狀態")
Life.SetState(&ZeroHP{})
Life.Request()
}
}
func (hp ZeroHP) Handle(Life *Life) {
if Life.HP <= 0 {
fmt.Println("玩家已死亡")
} else {
fmt.Println("強制玩家復活")
Life.SetState(&HighHP{})
}
}
main.go
package main
func main() {
p1 := Player{&Life{HP: 100, state: &HighHP{}}}
p1.DecreaseHP(10)
p1.DecreaseHP(20)
p1.DecreaseHP(20)
p1.DecreaseHP(20)
p1.DecreaseHP(20)
p1.DecreaseHP(20)
p1.Respawn()
p1.DecreaseHP(999)
p1.Respawn()
}
Console
健康狀態 HP 90
健康狀態->輕傷狀態
輕傷狀態 HP 70
輕傷狀態->重傷狀態
重傷狀態 HP 50
重傷狀態 HP 30
重傷狀態 HP 10
重傷狀態->死亡狀態
玩家已死亡
強制玩家復活
健康狀態->輕傷狀態
輕傷狀態->重傷狀態
重傷狀態->死亡狀態
玩家已死亡
強制玩家復活
思考總結
什么是狀態模式
狀態模式(State Pattern)中,類的行為是基于它的狀態改變的,這種型別的設計模式屬于行為型模式,
狀態模式中,我們創建表示各種狀態的物件和一個行為隨著狀態物件改變而改變的 context 物件,

狀態模式:允許物件(Context)在內部狀態發生改變時改變它的行為,物件看起來好像修改了它的類,
如果不用狀態模式,在多分支判斷呼叫各個行為導致方法過長,責任過大,面向物件設計其實就是希望做到代碼的責任分解,需要想辦法把各個行為變成一個又一個的類,增加時不會影響其他類,狀態的變化在各自的類中完成,
主要解決:
-
當控制一個物件狀態轉換的條件運算式過于復雜時的,把狀態的判斷邏輯轉移到不同狀態的一系列類當中,
-
物件的行為依賴于它的狀態(屬性),并且可以根據它的狀態改變而改變它的相關行為,
何時使用:代碼中包含大量與物件狀態有關的條件陳述句,
如何解決:將各種具體的狀態類抽象出來,
應用實體:
- 打籃球的時候運動員可以有正常狀態、不正常狀態和超常狀態,
優點:
- 封裝了轉換規則,狀態轉移是在各個具體狀態中進行的,用戶無需知道狀態轉移程序,
- 列舉可能的狀態,在列舉狀態之前需要確定狀態種類,
- 將所有與某個狀態有關的行為放到一個類中,并且可以方便地增加新的狀態,只需要改變物件狀態即可改變物件的行為,
- 允許狀態轉換邏輯與狀態物件合成一體,而不是某一個巨大的條件陳述句塊,
- 可以讓多個環境物件共享一個狀態物件,從而減少系統中物件的個數,
缺點:
- 狀態模式的使用必然會增加系統類和物件的個數,
- 狀態模式的結構與實作都較為復雜,如果使用不當將導致程式結構和代碼的混亂,
- 狀態模式對"開閉原則"的支持并不太好,對于可以切換狀態的狀態模式,增加新的狀態類需要修改那些負責狀態轉換的源代碼,否則無法切換到新增狀態,而且修改某個狀態類的行為也需修改對應類的源代碼,
使用場景:
- 行為隨狀態改變而改變的場景,
- 條件、分支陳述句的代替者,
注意事項:在行為受狀態約束的時候使用狀態模式,而且狀態不超過 5 個,
參考資料
- 《Go語言核心編程》李文塔
- 《Go語言高級編程》柴樹彬、曹春輝
- 《大話設計模式》程杰
- 單例模式 | 菜鳥教程
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/506129.html
標籤:其他
上一篇:day36-IO流03
下一篇:快取與資料庫結合使用的痛點
