设计模式:状态模式(State)

设计模式:状态模式(State)

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

状态模式的角色

  1. 环境角色Context):也称上下文,定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
  2. 抽象状态角色(State):定义一个接口,用以封装环境对象的一个特定的状态所对应的行为。
  3. 具体状态角色(ConcreteState):每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

案例

以酒店订房为例,房间的状态有:空闲、预订、入住。那么空闲房间的状态可以转变为:预订、入住。已预订状态房间的状态可以转变为:入住、取消预订。已入住房间的状态可以转变为:退房

1 状态接口State

public interface State
{
public void bookRoom();
public void unsubscribeRoom();
public void checkInRoom();
public void checkOutRoom();
}

2 房间类Room(环境角色)

public class Room
{
private State freeTimeState;
private State checkInState;
private State bookedState;

private State state;

public Room()
{
freeTimeState = new FreeTimeState(this);
checkInState = new CheckInState(this);
bookedState = new BookedState(this);
state = freeTimeState;
}

public void bookRoom()
{
state.bookRoom();
}
public void unsubscribeRoom()
{
state.unsubscribeRoom();
}
public void checkInRoom()
{
state.checkInRoom();
}
public void checkOutRoom()
{
state.checkOutRoom();
}

public String toString()
{
return "该房间的状态是:"+getState().getClass().getName();
}

public State getFreeTimeState()
{
return freeTimeState;
}

public void setFreeTimeState(State freeTimeState)
{
this.freeTimeState = freeTimeState;
}

public State getCheckInState()
{
return checkInState;
}

public void setCheckInState(State checkInState)
{
this.checkInState = checkInState;
}

public State getBookedState()
{
return bookedState;
}

public void setBookedState(State bookedState)
{
this.bookedState = bookedState;
}

public State getState()
{
return state;
}

public void setState(State state)
{
this.state = state;
}
}

3 房间状态(具体状态角色)

空闲状态

public class FreeTimeState implements State
{
private Room hotelManagement;

public FreeTimeState(Room hotelManagement)
{
this.hotelManagement = hotelManagement;
}
@Override
public void bookRoom()
{
System.out.println("您已经预定成功了!");
this.hotelManagement.setState(this.hotelManagement.getBookedState());
}

@Override
public void unsubscribeRoom()
{
}

@Override
public void checkInRoom()
{
System.out.println("您已经入住了!");
this.hotelManagement.setState(this.hotelManagement.getCheckInState());
}

@Override
public void checkOutRoom()
{
}
}

入住状态

public class CheckInState implements State
{
private Room hotelManagement;

public CheckInState(Room hotelManagement)
{
this.hotelManagement = hotelManagement;
}
@Override
public void bookRoom()
{
System.out.println("该房间已经入住了");
}

@Override
public void unsubscribeRoom()
{
}

@Override
public void checkInRoom()
{
System.out.println("该房间已经入住了");
}

@Override
public void checkOutRoom()
{
System.out.println("退房成功");
this.hotelManagement.setState(this.hotelManagement.getFreeTimeState());
}
}

预订状态

public class BookedState implements State
{
private Room hotelManagement;

public BookedState(Room hotelManagement)
{
this.hotelManagement = hotelManagement;
}

@Override
public void bookRoom()
{
System.out.println("该房间已经预定了");
}

@Override
public void unsubscribeRoom()
{
System.out.println("成功退订");
this.hotelManagement.setState(this.hotelManagement.getFreeTimeState());
}

@Override
public void checkInRoom()
{
System.out.println("入住成功");
this.hotelManagement.setState(this.hotelManagement.getCheckInState());
}

@Override
public void checkOutRoom()
{
}
}

4 测试代码

Room[] rooms = new Room[2];
for(int i=0;i<rooms.length;i++)
{
rooms[i] = new Room();
}

rooms[0].bookRoom();
rooms[0].checkInRoom();
rooms[0].bookRoom();
System.out.println(rooms[0]);
System.out.println("-------------");

rooms[1].checkInRoom();
rooms[1].bookRoom();
rooms[1].checkOutRoom();
rooms[1].bookRoom();
System.out.println(rooms[1]);

输出:

您已经预定成功了!
入住成功
该房间已经入住了
该房间的状态是:design.state.CheckInState
-------------
您已经入住了!
该房间已经入住了
退房成功
您已经预定成功了!
该房间的状态是:design.state.BookedState

优缺点

优点:

  1. 封装了转换规则。
  2. 枚举可能的状态,在枚举状态之前需要确定状态种类。
  3. 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
  4. 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。

缺点:

  1. 状态模式的使用必然会增加系统类的对象的个数
  2. 状态模式的结构与实现都较为复杂,如果使用不当讲导致程序结构和代码的混乱。
  3. 状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

适用场景

  1. 对象的行为依赖于它的状态(属性)并且可以根据它的状态而改变它的相关行为
  2. 代码中包含大量与对象状态相关的条件语句

JDK中的状态模式:
java.util.Iterator
javax.faces.lifecycle.LifeCycle#execute()


参考资料

  1. 23种设计模式
  2. 细数JDK里的设计模式
  3. 设计模式读书笔记—–状态模式

欢迎支持笔者的作品《深入理解Kafka: 核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客(ID: hiddenkafka)。
本文作者: 朱小厮

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×