简介
状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态发生改变时改变其行为。状态模式主要解决的是当一个对象的行为取决于它的状态,并且在运行时可以根据状态改变其行为的情况。
在状态模式中,对象将其内部的状态委托给表示不同状态的对象,使得在不同状态下可以切换不同的行为。这样可以使得对象的状态转换更加灵活,并且将状态相关的行为封装在具体的状态类中,符合开闭原则。
我们的车,有一个按钮是儿童锁,如果上锁那就所有的车门都不能打开,如果是解锁,那就可以打开车门,保障了儿童误操作突然打开车门。我们来实现下。
Demo
// State 抽象状态接口
type State interface {
Handle()
}
// Car 车辆对象,维护一个对具体状态对象的引用
type Car struct {
state State
}
func (c *Car) SetState(state State) {
c.state = state
}
func (c *Car) Request() {
c.state.Handle()
}
// ChildLock 具体状态A
type ChildLock struct{}
func (s *ChildLock) Handle() {
fmt.Println("儿童锁上锁,此时车门不能打开")
}
type ChildUnLock struct {
}
func (s *ChildUnLock) Handle() {
fmt.Println("儿童锁解锁,此时车门可以打开")
}
test
func TestState(t *testing.T) {
car := &Car{}
lock := &ChildLock{}
car.SetState(lock) // 车辆上儿童锁
car.Request()
unlock := &ChildUnLock{}
car.SetState(unlock) // 车辆解锁儿童锁
car.Request()
}
在这个示例中,Car 是车辆的整体,维护一个对具体状态对象的引用。State 是抽象状态接口,定义了具体状态对象要实现的方法。ChildLock 和 ChildUnLock 是具体状态类,实现了抽象状态接口的方法。
在客户端,我们创建了一辆车Car,并初始化状态为 ChildLock。通过调用 Request 方法,上下文对象委托当前状态对象处理请求。
然后,我们将状态切换为 ChildUnLock,再次调用 Request 方法,上下文对象委托新的状态对象处理请求。
作用和场景
- 将状态相关的行为封装在具体状态类中
状态模式将对象的行为随状态的改变而改变,将状态相关的逻辑封装在具体状态类中,使得每个状态类负责一组特定的行为。
- 消除大量的条件语句
通过将状态的判断逻辑分散到具体状态类中,可以避免使用大量的条件语句来判断对象的状态,使得代码更加清晰和可维护。比如我们就没有看到if lock怎样,if unlock怎样,都是通过状态来去维护的。
- 支持开闭原则
添加新的状态类时,不需要修改原有的代码,符合开闭原则。
当一个对象的行为在其内部状态改变时而改变,且可以在运行时动态地改变状态,适合使用状态模式。
当对象的状态判断逻辑包含大量的条件语句,可以考虑使用状态模式来替代这些条件语句,使得代码更加清晰和可维护。
总体而言,状态模式可以使得对象在不同状态下表现出不同的行为,通过将状态相关的逻辑封装在具体状态类中,使得代码更加灵活和可扩展。