找回密码
 立即注册
首页 业界区 业界 设计模式之状态模式(三分钟学会一个设计模式) ...

设计模式之状态模式(三分钟学会一个设计模式)

蓝娅萍 2025-6-6 12:45:04
状态模式(State Pattern)的定义是这样的:类的行为是基于它的状态改变的。
注意这里的状态不是狭义的指对象维护了一个“状态”字段,我们传入了不同的枚举值,对象整体的表现行为(对外方法)就改变了。
而是指内部的(任意)字段如果发生了变化,那么它的状态就变了,那么它对外的表现形式就变了。
状态模式是面向对象的23种设计模式中的一种,属于行为模式的范围。
通常我们在解决不同状态下,对外方法的不同表现时,可以定义若干的枚举,然后写一大堆if、 elseif、 switch等选择命令来区分不同的状态,然后走不同的业务分支。
而状态模式是支持将这些分支业务抽离出一个独立类(状态类),我们通过传入不同的状态类,就可以动态的执行不同的业务方法。
整体的结构大概是这样的:
1.jpeg

业务类维护了一个内部状态对象,这个状态对象支持由外部传入,切换为不同的状态对象。
而这些状态对象都统一实现了具体的方法,业务类内部在执行业务方法时,会调用这些状态对象中实现的方法。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )这样在切换状态时,业务方法就会调用不同的状态对象的方法了。从面向对象的角度,实现了状态变化,类行为的同步变化。
来看一个具体的代码示例:
类图如下
2.jpeg

 
 
枚举类
  1. 1 package com.example.demo.learn.pattern.behavior.status;
  2. 2
  3. 3 public enum TextStatusEnum {
  4. 4     ONLY_READ,
  5. 5     READ_WRITE,
  6. 6     UNAVAILABLE;
  7. 7
  8. 8 }
复制代码
状态定义接口
  1. 1 package com.example.demo.learn.pattern.behavior.status;
  2. 2
  3. 3 /**
  4. 4  * @discription
  5. 5  */
  6. 6 public interface TextState {
  7. 7      TextStatusEnum getStatus();
  8. 8
  9. 9      void write(String content);
  10. 10
  11. 11      void clear();
  12. 12
  13. 13      String read();
  14. 14
  15. 15      void setContent(StringBuilder sb);
  16. 16 }
复制代码
只读状态
  1. 1 package com.example.demo.learn.pattern.behavior.status;
  2. 2
  3. 3 import lombok.Data;
  4. 4 import lombok.extern.slf4j.Slf4j;
  5. 5
  6. 6 /**
  7. 7  * @discription
  8. 8  */
  9. 9 @Slf4j
  10. 10 @Data
  11. 11 public class OnlyReadState implements TextState {
  12. 12     private static final TextStatusEnum textStatus = TextStatusEnum.ONLY_READ;
  13. 13
  14. 14     private StringBuilder sb;
  15. 15
  16. 16     @Override
  17. 17     public TextStatusEnum getStatus() {
  18. 18         return textStatus;
  19. 19     }
  20. 20
  21. 21     public void write(String content) {
  22. 22         log.error("sorry, you can not write");
  23. 23     }
  24. 24
  25. 25     public void clear() {
  26. 26         log.error("sorry, you can not clear");
  27. 27     }
  28. 28
  29. 29     public String read() {
  30. 30         return sb.toString();
  31. 31     }
  32. 32
  33. 33     @Override
  34. 34     public void setContent(StringBuilder sb) {
  35. 35         this.sb = sb;
  36. 36     }
  37. 37 }
复制代码
读写状态
  1. 1 package com.example.demo.learn.pattern.behavior.status;
  2. 2
  3. 3 import lombok.Data;
  4. 4 import lombok.extern.slf4j.Slf4j;
  5. 5
  6. 6 /**
  7. 7  * @discription
  8. 8  */
  9. 9 @Data
  10. 10 @Slf4j
  11. 11 public class ReadWriteState implements TextState {
  12. 12     private static final TextStatusEnum textStatus = TextStatusEnum.ONLY_READ;
  13. 13
  14. 14     private StringBuilder sb = new StringBuilder();
  15. 15
  16. 16     @Override
  17. 17     public TextStatusEnum getStatus() {
  18. 18         return textStatus;
  19. 19     }
  20. 20
  21. 21     public void write(String content) {
  22. 22         sb.append(content);
  23. 23     }
  24. 24
  25. 25     public void clear() {
  26. 26         sb.setLength(0);
  27. 27     }
  28. 28
  29. 29     public String read() {
  30. 30         return sb.toString();
  31. 31     }
  32. 32
  33. 33     @Override
  34. 34     public void setContent(StringBuilder sb) {
  35. 35         this.sb = sb;
  36. 36     }
  37. 37 }
复制代码
本文编辑器(业务类/上下文)
  1. 1 package com.example.demo.learn.pattern.behavior.status;
  2. 2
  3. 3 import lombok.Data;
  4. 4 import lombok.extern.slf4j.Slf4j;
  5. 5
  6. 6 /**
  7. 7  * @discription
  8. 8  */
  9. 9 @Slf4j
  10. 10 public class TextEditor {
  11. 11
  12. 12     private StringBuilder sb = new StringBuilder();
  13. 13
  14. 14     private TextState textState;
  15. 15
  16. 16     public void setState(TextState textState) {
  17. 17         textState.setContent(sb);
  18. 18         this.textState = textState;
  19. 19     }
  20. 20
  21. 21     public void write(String content) {
  22. 22         if (textState == null) {
  23. 23             log.error("no state exist");
  24. 24             return;
  25. 25         }
  26. 26         textState.write(content);
  27. 27     }
  28. 28
  29. 29     public void clear() {
  30. 30         if (textState == null) {
  31. 31             log.error("no state exist");
  32. 32             return;
  33. 33         }
  34. 34         textState.clear();
  35. 35     }
  36. 36
  37. 37     public String read() {
  38. 38         if (textState == null) {
  39. 39             log.error("no state exist");
  40. 40             return "no state";
  41. 41         }
  42. 42         return textState.read();
  43. 43     }
  44. 44
  45. 45 }
复制代码
主类
  1. 1 package com.example.demo.learn.pattern.behavior.status;
  2. 2
  3. 3 import lombok.extern.slf4j.Slf4j;
  4. 4
  5. 5 /**
  6. 6  * @discription
  7. 7  */
  8. 8 @Slf4j
  9. 9 public class PatternMain {
  10. 10     public static void main(String[] args) {
  11. 11         TextEditor editor = new TextEditor();
  12. 12         String text;
  13. 13
  14. 14         //可读写状态
  15. 15         TextState rw = new ReadWriteState();
  16. 16         editor.setState(rw);
  17. 17         for (int i = 0; i < 3; i++) {
  18. 18             editor.write("write" + i);
  19. 19             text = editor.read();
  20. 20             log.warn("read :" + text);
  21. 21         }
  22. 22         editor.clear();
  23. 23         text = editor.read();
  24. 24         log.warn("after clear, we read :" + text);
  25. 25         editor.write("last write");
  26. 26
  27. 27         log.warn("-----------------------now, we exchange state to only read-----------------------" );
  28. 28         //只读状态
  29. 29         TextState or = new OnlyReadState();
  30. 30         editor.setState(or);
  31. 31         for (int i = 0; i < 3; i++) {
  32. 32             editor.write("write" + i);
  33. 33             text = editor.read();
  34. 34             log.warn("read :" + text);
  35. 35         }
  36. 36         editor.clear();
  37. 37         text = editor.read();
  38. 38         log.warn("after clear, we read :" + text);
  39. 39     }
  40. 40 }
复制代码
输出效果如下:
  1. 10:02:52.356 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :write0
  2. 10:02:52.368 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :write0write1
  3. 10:02:52.369 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :write0write1write2
  4. 10:02:52.371 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - after clear, we read :(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )
  5. 10:02:52.372 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - -----------------------now, we exchange state to only read-----------------------
  6. 10:02:52.376 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState - sorry, you can not write
  7. 10:02:52.378 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :last write
  8. 10:02:52.378 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState - sorry, you can not write
  9. 10:02:52.378 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :last write
  10. 10:02:52.379 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState - sorry, you can not write
  11. 10:02:52.379 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :last write
  12. 10:02:52.379 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState - sorry, you can not clear
  13. 10:02:52.380 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - after clear, we read :last write
  14. Process finished with exit code 0
复制代码
我们可以看到在最初设置读写状态后,可以做读、写、清除等操作
在设置读状态后则只能读了。
这样回头来看,其实我们就是将不同if Switch的选择分支,连同选择的状态,一同封装到不同的状态类中,我们需要新增一种分支逻辑,不再需要修改选择分支,而是只需要新增一个状态类即可。
那是否状态模式可以替代传统的if 选择分支,答案是不能,本质上还是一个度的原因,面相对象如果过度设计,会导致类的数量无限膨胀,难以维护,试想如果存在多个状态字段(status、type等),则实体对象的状态是由多个状态字段组合而成的,每增加一个新的状态字段,都会导致状态的数量快速增加,这显然不是我们想看到的。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册