概念:

  State模式也叫状态模式,是行为设计模式的一种。State模式允许通过改变对象的内部状态而改变对象的行为,这个对象表现得就好像修改了它的类一样。

  根据这个概念,我们举个例子

 public class Behavior {
private int time; public int getTime() {
return time;
} public void setTime(int time) {
this.time = time;
} public void eat(){
if(time == 7){
System.out.println("吃早饭");
}else if(time == 12){
System.out.println("吃午饭");
}else if(time == 18){
System.out.println("吃晚饭");
}else{
System.out.println("还不到吃饭时间");
}
}
}
 public class MainClass {
public static void main(String[] args) {
Behavior behavior = new Behavior();
behavior.setTime(7);
behavior.eat(); behavior.setTime(12);
behavior.eat(); behavior.setTime(18);
behavior.eat(); behavior.setTime(20);
behavior.eat();
}
}

  结果:

  可以看到,根据time属性的不同,对象的行为也发生了改变,但是这样的方式很不好,所有的事情都放到了eat()方法中,导致eat()方法过于复杂

  下面就看一看状态模式

  状态模式的应用场景

  状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转译到表现不同状态的一系列类当中,可以把复杂的判断逻辑简化。

  简单来说:

  1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  2.一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。

  状态模式的结构

  

  状态模式的角色和职责

  1、Context:用户对象:拥有一个State类型的成员,以标识对象的当前状态(Behavior)

  2、State:接口或基类封装与Context的特定状态相关的行为;

  3、ConcreteState:接口实现类或子类实现了一个与Context某个状态相关的行为。

  按照状态模式,我们来改造一下,刚才的例子,吃早中晚饭,不是吃饭时间,都是状态,所以我们把状态单独封装出来。

  首先,新建一个State

 public abstract class State {
public abstract void eat();
}

  接着新建ConcreteState

 /*
* 早餐
*/
public class BreakfastState extends State { @Override
public void eat() {
System.out.println("吃早餐");
} }
 /*
* 午餐
*/
public class LunchState extends State { @Override
public void eat() {
System.out.println("吃午餐");
} }
 /*
* 晚餐
*/
public class DinnerState extends State { @Override
public void eat() {
System.out.println("吃晚餐");
} }
 /*
* 不是吃饭时间
*/
public class NoFoodState extends State { @Override
public void eat() {
System.out.println("不是吃饭时间");
} }

  再修改一下behavior

 public class Behavior {
private int time;
State state = null; public int getTime() {
return time;
} public void setTime(int time) {
this.time = time;
} public void eat(){
if(time == 7){
state = new BreakfastState();
state.eat();
}else if(time == 12){
state = new LunchState();
state.eat();
}else if(time == 18){
state = new DinnerState();
state.eat();
}else{
state = new NoFoodState();
state.eat();
}
}
}

  这样,和刚才的结果一样,但是这样子,判断逻辑还是在对象中,我们继续修改,将逻辑写到ConcreteState

  因为,我们要知道time,所以需要向state中传入参数,所以我们将Behavior传进去

 public abstract class State {
public abstract void eat(Behavior behavior);
}

  然后,修改Behavior

 public class Behavior {
private int time;
State state = null; public Behavior() {
state = new BreakfastState();
} public int getTime() {
return time;
} public void setTime(int time) {
this.time = time;
} public State getState() {
return state;
} public void setState(State state) {
this.state = state;
} public void eat(){
//逻辑取出,所以这里只剩调用方法
state.eat(this);
//当所有方法都完成后,回到最初始状态
state = new BreakfastState();
}
}

  接着,再继续修改每一个ConcreteState

 /*
* 早餐
*/
public class BreakfastState extends State { @Override
public void eat(Behavior behavior) {
if(behavior.getTime() == 7){
System.out.println("吃早餐");
}else{
//如果不符合条件,重置state为下一个状态
behavior.setState(new LunchState());
behavior.eat();
}
}
}
 /*
* 午餐
*/
public class LunchState extends State { @Override
public void eat(Behavior behavior) {
if(behavior.getTime() == 12){
System.out.println("吃午餐");
}else{
behavior.setState(new DinnerState());
behavior.eat();
}
} }
 /*
* 晚餐
*/
public class DinnerState extends State { @Override
public void eat(Behavior behavior) {
if(behavior.getTime() == 18){
System.out.println("吃晚餐");
}else{
behavior.setState(new NoFoodState());
behavior.eat();
}
} }
 /*
* 不是吃饭时间
*/
public class NoFoodState extends State { @Override
public void eat(Behavior behavior) {
System.out.println("不是吃饭时间");
} }

  这样,结果和之前是一样的

  状态模式的优点与缺点

  优点: 1、封装了转换规则。

      2、枚举可能的状态,在枚举状态之前需要确定状态种类。

      3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。

      4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。

      5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

  缺点: 1、状态模式的使用必然会增加系统类和对象的个数。

      2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。

        3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

 注意事项:在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。

java设计模式-----22、状态模式的更多相关文章

  1. 折腾Java设计模式之状态模式

    原文地址 折腾Java设计模式之状态模式 状态模式 在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式.在状态模式中,我们创建表示各种状态的对象 ...

  2. JAVA设计模式--State(状态模式)

    状态模式(State Pattern)是设计模式的一种,属于行为模式. 定义(源于Design Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要 ...

  3. JAVA设计模式:状态模式

    声明:转载请说明来源:http://www.cnblogs.com/pony1223/p/7518226.html 一.引出状态模式 假设我们现在有一个糖果机项目,那么我们知道正常一般糖果机提供给用户 ...

  4. Java设计模式之状态模式详解

    (本文由言念小文原创,转载请注明出处) 在实际工作中经常遇到某个对象,处于不同的状态有不同行为逻辑.且状态之间可以相互迁移的业务场景,特别是在开发通信协议栈类软件中尤为多见.<设计模式之禅> ...

  5. java设计模式之状态模式

    状态模式 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类. 状态模式UML图 上下文环境(Context):它定义了客户程序需要的接口并维护一个具体状态角色的实例,将与状态相关 ...

  6. 曾侯乙编钟引发的遐想之Java设计模式:状态模式

    目录 示例 简单例子 改进代码 状态模式 定义 意图 主要解决问题 何时使用 优缺点 曾侯乙编钟 状态模式-命令模式-策略模式 示例 一个类对外提供了多个行为,同时该类对象有多种状态,不同状态下对外的 ...

  7. 乐在其中设计模式(C#) - 状态模式(State Pattern)

    原文:乐在其中设计模式(C#) - 状态模式(State Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允 ...

  8. 折腾Java设计模式之备忘录模式

    原文地址:折腾Java设计模式之备忘录模式 备忘录模式 Without violating encapsulation, capture and externalize an object's int ...

  9. 折腾Java设计模式之访问者模式

    博客原文地址:折腾Java设计模式之访问者模式 访问者模式 Represent an operation to be performed on the elements of an object st ...

  10. 折腾Java设计模式之命令模式

    博客原文地址 折腾Java设计模式之命令模式 命令模式 wiki上的描述 Encapsulate a request as an object, thereby allowing for the pa ...

随机推荐

  1. Python 生成器, 迭代器, 可迭代对象的区别

    1.可迭代对象 在python中, 一切皆对象, 但凡是可以用for循环进行遍历取值的对象都可以称之为可迭代对象, 可迭代对象在程序的一个执行周期中,可以无限轮次的进行循环遍历 2.迭代器 a.一个可 ...

  2. poi 读取使用 Strict Open XML 保存的 excel 文档

    poi 读取使用 Strict Open XML 保存的 excel 文档 某项目有一个功能需要读取 excel 报表内容,使用poi读取时报错: 具体错误为: org.apache.poi.POIX ...

  3. 编译lua-5.3.5时出错解决方法

    问题描述: 执行 make linux test 过程出现错误,错误信息如下: “ lua.c:82:31: fatal error: readline/readline.h: No such fil ...

  4. JSONP是什么

    摘自:https://segmentfault.com/a/1190000007935557 一.JSONP的诞生 首先,因为ajax无法跨域,然后开发者就有所思考 其次,开发者发现, <scr ...

  5. Alpha冲刺(3/10)——追光的人

    1.队友信息 队员学号 队员博客 221600219 小墨 https://www.cnblogs.com/hengyumo/ 221600240 真·大能猫 https://www.cnblogs. ...

  6. inotify监听文件夹的变动

    inotify只能监控单层目录变化,不能监控子目录中的变化情况.如果需要监控子目录,需要在调用inotify_add_watch(int fd, char *dir, int mask):int建立监 ...

  7. Android入门学习总结

    1.Manifest.xml是程序运行时读取的文件,是核心的配置文件:也是从中读取Activity 2.主要的代码文件存放在MainActivity.java,里面固定会有onCreate函数会通过s ...

  8. docker with redis

    docker run --name myredis -d -v /home/rudy/pro/database/redis:/data -p : --privileged=true redis

  9. webkit技术内幕读书笔记 (一)

    本文部分摘录自互联网. Chromeium与Chrome Chromium是Google为发展自家的浏览器Google Chrome而打开的项目,所以Chromium相当于Google Chrome的 ...

  10. shell脚本补缺

    一.执行脚本的三种方法. chmod  +x  添加执行权限 ./example.sh        相对路径 root/test/example.sh  绝对路径 bash example.sh   ...