状态

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

状态模式(State)经常用在带有状态的对象中。

什么是状态?我们以QQ聊天为例,一个用户的QQ有几种状态:

  • 离线状态(尚未登录);
  • 正在登录状态;
  • 在线状态;
  • 忙状态(暂时离开)。

如何表示状态?我们定义一个enum就可以表示不同的状态。但不同的状态需要对应不同的行为,比如收到消息时:

  1. if (state == ONLINE) {
  2. // 闪烁图标
  3. } else if (state == BUSY) {
  4. reply("现在忙,稍后回复");
  5. } else if ...

状态模式的目的是为了把上述一大串if…else…的逻辑给分拆到不同的状态类中,使得将来增加状态比较容易。

例如,我们设计一个聊天机器人,它有两个状态:

  • 未连线;
  • 已连线。

对于未连线状态,我们收到消息也不回复:

  1. public class DisconnectedState implements State {
  2. public String init() {
  3. return "Bye!";
  4. }
  5. public String reply(String input) {
  6. return "";
  7. }
  8. }

对于已连线状态,我们回应收到的消息:

  1. public class ConnectedState implements State {
  2. public String init() {
  3. return "Hello, I'm Bob.";
  4. }
  5. public String reply(String input) {
  6. if (input.endsWith("?")) {
  7. return "Yes. " + input.substring(0, input.length() - 1) + "!";
  8. }
  9. if (input.endsWith(".")) {
  10. return input.substring(0, input.length() - 1) + "!";
  11. }
  12. return input.substring(0, input.length() - 1) + "?";
  13. }
  14. }

状态模式的关键设计思想在于状态切换,我们引入一个BotContext完成状态切换:

  1. public class BotContext {
  2. private State state = new DisconnectedState();
  3. public String chat(String input) {
  4. if ("hello".equalsIgnoreCase(input)) {
  5. // 收到hello切换到在线状态:
  6. state = new ConnectedState();
  7. return state.init();
  8. } else if ("bye".equalsIgnoreCase(input)) {
  9. / 收到bye切换到离线状态:
  10. state = new DisconnectedState();
  11. return state.init();
  12. }
  13. return state.reply(input);
  14. }
  15. }

这样,一个价值千万的AI聊天机器人就诞生了:

  1. Scanner scanner = new Scanner(System.in);
  2. BotContext bot = new BotContext();
  3. for (;;) {
  4. System.out.print("> ");
  5. String input = scanner.nextLine();
  6. String output = bot.chat(input);
  7. System.out.println(output.isEmpty() ? "(no reply)" : "< " + output);
  8. }

试试效果:

  1. > hello
  2. < Hello, I'm Bob.
  3. > Nice to meet you.
  4. < Nice to meet you!
  5. > Today is cold?
  6. < Yes. Today is cold!
  7. > bye
  8. < Bye!

练习

状态 - 图1下载练习:新增BusyState状态表示忙碌 (推荐使用IDE练习插件快速下载)

小结

状态模式的设计思想是把不同状态的逻辑分离到不同的状态类中,从而使得增加新状态更容易;

状态模式的实现关键在于状态转换。简单的状态转换可以直接由调用方指定,复杂的状态转换可以在内部根据条件触发完成。

读后有收获可以支付宝请作者喝咖啡,读后有疑问请加微信群讨论:

状态 - 图2状态 - 图3