awesome-patterns/behavioral/state/problem.go
2019-05-03 10:48:46 +08:00

119 lines
2.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 存疑部分.
//
// 这里是以玩家的健康状态为基准,影响生命回复和受到伤害的例子,有三个状态[健康HealthyState|受伤WoundedState|死亡DeadState].
// 和main.go中的跷跷板例子由行为驱动状态变化不同.以下例子的行为是受到数据影响的,结果就是达不到完全消除if-else的效果
//
// 疑问:
// 1. 很多地方说状态模式可以消除if-else事实上要做到自行的状态切换很多时候还是会用到if-else这里的消除应当是指
// 将巨大的条件语句拆分开(?)
// 2. 还是说这种由数据决定状态的事务逻辑下不适合使用状态模式
package main
import (
"errors"
"fmt"
)
// state
type PlayerState interface {
Heal(p *Player) error
Hurt(p *Player ,dmg int)
}
type HealthyState struct {}
func (h HealthyState)Heal(p *Player) error{
return nil
}
func (h HealthyState)Hurt(p *Player ,dmg int){
if dmg > 0 && dmg < p.MaxHealth{
p.Health = p.Health - dmg
p.State = WoundedState{}
}else if dmg > p.MaxHealth{
p.Health = 0
p.State = DeadState{}
}
}
type WoundedState struct {}
func (WoundedState)Heal(p *Player) error{
if p.Health >= p.MaxHealth - 5{
fmt.Printf("healing from %d to %d\n" ,p.Health ,p.MaxHealth)
p.State = HealthyState{}
p.Health = p.MaxHealth
}else{
fmt.Printf("healing from %d to %d\n" ,p.Health ,p.Health+5)
p.Health = p.Health + 5
}
return nil
}
func (h WoundedState)Hurt(p *Player ,dmg int){
if p.Health > dmg{
p.Health = p.Health - dmg
}else {
p.State = DeadState{}
p.Health = 0
}
}
type DeadState struct {}
func (DeadState)Heal(P *Player) error{
return errors.New("you are dead")
}
func (DeadState)Hurt(P *Player ,dmg int){}
// context
type Player struct {
Health int
MaxHealth int
State PlayerState
}
func (p *Player)HealPlayer()error{
return p.State.Heal(p)
}
func (p *Player)HurtPlayer(damage int){
fmt.Printf("damage %d\n" ,damage)
p.State.Hurt(p ,damage)
}
//func main(){
// player := &Player{
// Health:100,
// MaxHealth:100,
// State:HealthyState{},
// }
//
// rand.Seed(time.Now().UnixNano())
// for i:=0 ;i<10 ;i++{
// if err := player.HealPlayer();err != nil{
// fmt.Println(err)
// break
// }
// player.HurtPlayer(rand.Intn(30))
// }
// /*
// output:
// damage 28
// healing from 72 to 77
// damage 29
// healing from 48 to 53
// damage 15
// healing from 38 to 43
// damage 1
// healing from 42 to 47
// damage 19
// healing from 28 to 33
// damage 27
// healing from 6 to 11
// damage 16
// you are dead
// */
//}