状态模式(State Pattern)的定义是这样的:
类的行为是基于它的状态改变的。

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

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

枚举类

1 packagecom.example.demo.learn.pattern.behavior.status;2 
3 public enumTextStatusEnum {4 ONLY_READ,5 READ_WRITE,6 UNAVAILABLE;7 
8 }

状态定义接口

1 packagecom.example.demo.learn.pattern.behavior.status;2 
3 /**
4 * @discription5  */
6 public interfaceTextState {7 TextStatusEnum getStatus();8 
9      voidwrite(String content);10 
11      voidclear();12 
13 String read();14 
15      voidsetContent(StringBuilder sb);16 }

只读状态

1 packagecom.example.demo.learn.pattern.behavior.status;2 
3 importlombok.Data;4 importlombok.extern.slf4j.Slf4j;5 
6 /**
7 * @discription8  */
9 @Slf4j10 @Data11 public class OnlyReadState implementsTextState {12     private static final TextStatusEnum textStatus =TextStatusEnum.ONLY_READ;13 
14     privateStringBuilder sb;15 
16 @Override17     publicTextStatusEnum getStatus() {18         returntextStatus;19 }20 
21     public voidwrite(String content) {22         log.error("sorry, you can not write");23 }24 
25     public voidclear() {26         log.error("sorry, you can not clear");27 }28 
29     publicString read() {30         returnsb.toString();31 }32 
33 @Override34     public voidsetContent(StringBuilder sb) {35         this.sb =sb;36 }37 }

读写状态

1 packagecom.example.demo.learn.pattern.behavior.status;2 
3 importlombok.Data;4 importlombok.extern.slf4j.Slf4j;5 
6 /**
7 * @discription8  */
9 @Data10 @Slf4j11 public class ReadWriteState implementsTextState {12     private static final TextStatusEnum textStatus =TextStatusEnum.ONLY_READ;13 
14     private StringBuilder sb = newStringBuilder();15 
16 @Override17     publicTextStatusEnum getStatus() {18         returntextStatus;19 }20 
21     public voidwrite(String content) {22 sb.append(content);23 }24 
25     public voidclear() {26         sb.setLength(0);27 }28 
29     publicString read() {30         returnsb.toString();31 }32 
33 @Override34     public voidsetContent(StringBuilder sb) {35         this.sb =sb;36 }37 }

本文编辑器(业务类/上下文)

1 packagecom.example.demo.learn.pattern.behavior.status;2 
3 importlombok.Data;4 importlombok.extern.slf4j.Slf4j;5 
6 /**
7 * @discription8  */
9 @Slf4j10 public classTextEditor {11 
12     private StringBuilder sb = newStringBuilder();13 
14     privateTextState textState;15 
16     public voidsetState(TextState textState) {17 textState.setContent(sb);18         this.textState =textState;19 }20 
21     public voidwrite(String content) {22         if (textState == null) {23             log.error("no state exist");24             return;25 }26 textState.write(content);27 }28 
29     public voidclear() {30         if (textState == null) {31             log.error("no state exist");32             return;33 }34 textState.clear();35 }36 
37     publicString read() {38         if (textState == null) {39             log.error("no state exist");40             return "no state";41 }42         returntextState.read();43 }44 
45 }

主类

1 packagecom.example.demo.learn.pattern.behavior.status;2 
3 importlombok.extern.slf4j.Slf4j;4 
5 /**
6 * @discription7  */
8 @Slf4j9 public classPatternMain {10     public static voidmain(String[] args) {11         TextEditor editor = newTextEditor();12 String text;13 
14         //可读写状态
15         TextState rw = newReadWriteState();16 editor.setState(rw);17         for (int i = 0; i < 3; i++) {18             editor.write("write" +i);19             text =editor.read();20             log.warn("read :" +text);21 }22 editor.clear();23         text =editor.read();24         log.warn("after clear, we read :" +text);25         editor.write("last write");26 
27         log.warn("-----------------------now, we exchange state to only read-----------------------");28         //只读状态
29         TextState or = newOnlyReadState();30 editor.setState(or);31         for (int i = 0; i < 3; i++) {32             editor.write("write" +i);33             text =editor.read();34             log.warn("read :" +text);35 }36 editor.clear();37         text =editor.read();38         log.warn("after clear, we read :" +text);39 }40 }

输出效果如下:

10:02:52.356 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain -read :write010:02:52.368 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain -read :write0write110:02:52.369 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain -read :write0write1write210:02:52.371 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain -after clear, we read :(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )10:02:52.372 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - -----------------------now, we exchange state to only read-----------------------
10:02:52.376 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState -sorry, you can not write10:02:52.378 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain -read :last write10:02:52.378 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState -sorry, you can not write10:02:52.378 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain -read :last write10:02:52.379 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState -sorry, you can not write10:02:52.379 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain -read :last write10:02:52.379 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState -sorry, you can not clear10:02:52.380 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain -after clear, we read :last write

Process finished with exit code
0

我们可以看到在最初设置读写状态后,可以做读、写、清除等操作

在设置读状态后则只能读了。

这样回头来看,其实我们就是将不同if Switch的选择分支,连同选择的状态,一同封装到不同的状态类中,我们需要新增一种分支逻辑,不再需要修改选择分支,而是只需要新增一个状态类即可。
那是否状态模式可以替代传统的if 选择分支,答案是不能,本质上还是一个度的原因,面相对象如果过度设计,会导致类的数量无限膨胀,难以维护,试想如果存在多个状态字段(status、type等),则实体对象的状态是由多个状态字段组合而成的,每增加一个新的状态字段,都会导致状态的数量快速增加,这显然不是我们想看到的。

标签: none

添加新评论