状态模式(State Pattern)的定义是这样的:类的行为是基于它的状态改变的。
注意这里的状态不是狭义的指对象维护了一个“状态”字段,我们传入了不同的枚举值,对象整体的表现行为(对外方法)就改变了。
而是指内部的(任意)字段如果发生了变化,那么它的状态就变了,那么它对外的表现形式就变了。
状态模式是面向对象的23种设计模式中的一种,属于行为模式的范围。
通常我们在解决不同状态下,对外方法的不同表现时,可以定义若干的枚举,然后写一大堆if、 elseif、 switch等选择命令来区分不同的状态,然后走不同的业务分支。
而状态模式是支持将这些分支业务抽离出一个独立类(状态类),我们通过传入不同的状态类,就可以动态的执行不同的业务方法。
整体的结构大概是这样的:
业务类维护了一个内部状态对象,这个状态对象支持由外部传入,切换为不同的状态对象。
而这些状态对象都统一实现了具体的方法,业务类内部在执行业务方法时,会调用这些状态对象中实现的方法。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )这样在切换状态时,业务方法就会调用不同的状态对象的方法了。从面向对象的角度,实现了状态变化,类行为的同步变化。
来看一个具体的代码示例:
类图如下
枚举类- 1 package com.example.demo.learn.pattern.behavior.status;
- 2
- 3 public enum TextStatusEnum {
- 4 ONLY_READ,
- 5 READ_WRITE,
- 6 UNAVAILABLE;
- 7
- 8 }
复制代码 状态定义接口- 1 package com.example.demo.learn.pattern.behavior.status;
- 2
- 3 /**
- 4 * @discription
- 5 */
- 6 public interface TextState {
- 7 TextStatusEnum getStatus();
- 8
- 9 void write(String content);
- 10
- 11 void clear();
- 12
- 13 String read();
- 14
- 15 void setContent(StringBuilder sb);
- 16 }
复制代码 只读状态- 1 package com.example.demo.learn.pattern.behavior.status;
- 2
- 3 import lombok.Data;
- 4 import lombok.extern.slf4j.Slf4j;
- 5
- 6 /**
- 7 * @discription
- 8 */
- 9 @Slf4j
- 10 @Data
- 11 public class OnlyReadState implements TextState {
- 12 private static final TextStatusEnum textStatus = TextStatusEnum.ONLY_READ;
- 13
- 14 private StringBuilder sb;
- 15
- 16 @Override
- 17 public TextStatusEnum getStatus() {
- 18 return textStatus;
- 19 }
- 20
- 21 public void write(String content) {
- 22 log.error("sorry, you can not write");
- 23 }
- 24
- 25 public void clear() {
- 26 log.error("sorry, you can not clear");
- 27 }
- 28
- 29 public String read() {
- 30 return sb.toString();
- 31 }
- 32
- 33 @Override
- 34 public void setContent(StringBuilder sb) {
- 35 this.sb = sb;
- 36 }
- 37 }
复制代码 读写状态- 1 package com.example.demo.learn.pattern.behavior.status;
- 2
- 3 import lombok.Data;
- 4 import lombok.extern.slf4j.Slf4j;
- 5
- 6 /**
- 7 * @discription
- 8 */
- 9 @Data
- 10 @Slf4j
- 11 public class ReadWriteState implements TextState {
- 12 private static final TextStatusEnum textStatus = TextStatusEnum.ONLY_READ;
- 13
- 14 private StringBuilder sb = new StringBuilder();
- 15
- 16 @Override
- 17 public TextStatusEnum getStatus() {
- 18 return textStatus;
- 19 }
- 20
- 21 public void write(String content) {
- 22 sb.append(content);
- 23 }
- 24
- 25 public void clear() {
- 26 sb.setLength(0);
- 27 }
- 28
- 29 public String read() {
- 30 return sb.toString();
- 31 }
- 32
- 33 @Override
- 34 public void setContent(StringBuilder sb) {
- 35 this.sb = sb;
- 36 }
- 37 }
复制代码 本文编辑器(业务类/上下文)- 1 package com.example.demo.learn.pattern.behavior.status;
- 2
- 3 import lombok.Data;
- 4 import lombok.extern.slf4j.Slf4j;
- 5
- 6 /**
- 7 * @discription
- 8 */
- 9 @Slf4j
- 10 public class TextEditor {
- 11
- 12 private StringBuilder sb = new StringBuilder();
- 13
- 14 private TextState textState;
- 15
- 16 public void setState(TextState textState) {
- 17 textState.setContent(sb);
- 18 this.textState = textState;
- 19 }
- 20
- 21 public void write(String content) {
- 22 if (textState == null) {
- 23 log.error("no state exist");
- 24 return;
- 25 }
- 26 textState.write(content);
- 27 }
- 28
- 29 public void clear() {
- 30 if (textState == null) {
- 31 log.error("no state exist");
- 32 return;
- 33 }
- 34 textState.clear();
- 35 }
- 36
- 37 public String read() {
- 38 if (textState == null) {
- 39 log.error("no state exist");
- 40 return "no state";
- 41 }
- 42 return textState.read();
- 43 }
- 44
- 45 }
复制代码 主类- 1 package com.example.demo.learn.pattern.behavior.status;
- 2
- 3 import lombok.extern.slf4j.Slf4j;
- 4
- 5 /**
- 6 * @discription
- 7 */
- 8 @Slf4j
- 9 public class PatternMain {
- 10 public static void main(String[] args) {
- 11 TextEditor editor = new TextEditor();
- 12 String text;
- 13
- 14 //可读写状态
- 15 TextState rw = new ReadWriteState();
- 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 = new OnlyReadState();
- 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 :write0
- 10:02:52.368 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :write0write1
- 10:02:52.369 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :write0write1write2
- 10: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 write
- 10:02:52.378 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :last write
- 10:02:52.378 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState - sorry, you can not write
- 10:02:52.378 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :last write
- 10:02:52.379 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState - sorry, you can not write
- 10:02:52.379 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :last write
- 10:02:52.379 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState - sorry, you can not clear
- 10: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等),则实体对象的状态是由多个状态字段组合而成的,每增加一个新的状态字段,都会导致状态的数量快速增加,这显然不是我们想看到的。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |