状态模式---State
Posted 高高for 循环
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了状态模式---State相关的知识,希望对你有一定的参考价值。
状态模式
根据状态决定行为
定义:
GOF《设计模式》中给状态模式下的定义为:允许一个对象在其内部状态改变时改变它的行为。
- 能够让程序根据不同的外部情况来做出不同的响应,最直接的方法就是在程序中将这些 可能发生的外部情况全部考虑到,使用if else 语句来进行代码响应选择。但是这种方法对于复杂一点的状态判断,就会显得杂乱无章,容易产生错误,而且增加一个新的状态将会带来大量的修改。
- 这个时候“根据状态决定行为”的状态模式的引入也许是个不错的主意。状态模式可以有效的替换充满在程序中的 if else 语句:将不同条件下的行为封装在一个类里面,再给这些类一个统一的父类来约束他们
组成:
生活中的状态模式:
- 以水为例,水之三态,固、液、气,三种状态表现出不同的特性和行为,它们之间的转换也伴随着热力学的现象。
- 电梯,有运行状态、开门状态、闭门状态、停止状态等
- QQ来说,有几种状态,在线、隐身、忙碌等,每个状态对应不同的操作
- java线程分为:新建状态(New),就绪状态(Runnable),运行状态(Running),阻塞状态(Blocked),死亡状态(Dead)
案例1 :
需求:
- 一个漂亮的MM 有开心和悲伤两种状态,且不同转态下,MM说的话,和哭笑的动作,都会根据状态的不同而不同.
普通 if else来判断:
MM:
public class MM {
//姓名
String name;
//转态
MMState state;
//内置状态的类别,分为HAPPY,SAD2种
private enum MMState {HAPPY, SAD}
public void smile() {
if(state.equals(MMState.HAPPY)){
System.out.println("开怀大笑");
}else if(state.equals(MMState.SAD)){
System.out.println("无奈苦笑");
}
}
public void cry() {
if(state.equals(MMState.HAPPY)){
System.out.println("喜极而泣");
}else if(state.equals(MMState.SAD)){
System.out.println("嚎啕大哭");
}
}
public void say() {
if(state.equals(MMState.HAPPY)){
System.out.println("开心开心极了!!!");
}else if(state.equals(MMState.SAD)){
System.out.println("郁闷不说话!!!");
}
}
public void setHappy(){
this.state=MMState.HAPPY;
}
public void setSad(){
this.state=MMState.SAD;
}
}
测试:
public class Test01 {
public static void main(String[] args) {
MM mm = new MM();
//设置转态为开心
mm.setHappy();
//调用方法
mm.smile();
mm.cry();
mm.say();
//改变状态为Sad
mm.setSad();
System.out.println("------------改变状态为Sad---------");
//调用方法
mm.smile();
mm.cry();
mm.say();
}
}
状态模式实现:
抽象的转态角色:MMState
public abstract class MMState {
abstract void smile();
abstract void cry();
abstract void say();
}
具体的开心转态角色: MMHappyState
public class MMHappyState extends MMState {
@Override
void smile() {
System.out.println("开怀大笑");
}
@Override
void cry() {
System.out.println("喜极而泣");
}
@Override
void say() {
System.out.println("开心开心极了!!!");
}
}
具体的悲伤转态角色: MMSadState
public class MMSadState extends MMState {
@Override
void smile() {
System.out.println("无奈苦笑");
}
@Override
void cry() {
System.out.println("嚎啕大哭");
}
@Override
void say() {
System.out.println("郁闷不说话!!!");
}
}
使用环境角色: MM
此时MM的行为方法,会根据状态state不同而自动改变
且MM增加状态时,代码结构也不需要再改变.
public class MM {
//姓名
String name;
//状态 默认为开心状态
MMState state = new MMHappyState();
public void smile() {
state.smile();
}
public void cry() {
state.cry();
}
public void say() {
state.say();
}
}
测试
public class Test01 {
public static void main(String[] args) {
MM mm = new MM();
//设置转态为开心
mm.state=new MMHappyState();
mm.smile();
mm.cry();
mm.say();
//改变状态为Sad
mm.state=new MMSadState();
System.out.println("------------改变状态为Sad---------");
//调用方法
mm.smile();
mm.cry();
mm.say();
}
}
有限转态机(FWM)
状态模式(State Pattern) 和有限转态机(State Machine)是2个东西,不要混淆在一起
总结
使用场景:
- 对象的行为需要随着状态的改变而改变时。
- 当我们一个操作中需要根据状态来写大量的if/else逻辑时
优点:
- 通过将每个状态设置为独立的对象,消除了代码中存在的大量if/else等判断分支,使得代码更加简洁,更容易维护。
- 将不同的状态通过不同的类来表示,使得状态切换时相比较于用数字或者字符串来表示时更加直观,转换目的也更加明确。
- 每个状态类的职责单一明确,易于扩展。
缺点:
- 状态过多会引起类膨胀(事实上这也是大部分设计模式的通病)。
- 状态模式的结构与实现相对较为复杂,容易造成代码混乱。
- 对于支持状态切换的状态类违反了开闭原则,因为一旦状态修改或者中间要新增状态,则需要修改对应的源代码,否则会出现状态切换错误。
注意事项:
- 在行为受状态约束的情况下可以使用状态模式,使用时对象的状态最好不要超过5个
状态模式和策略模式对比:
状态模式和策略模式都能用来消除大量的if/else场景,但是也有本质区别。
- 策略模式中各个策略之间是独立的,相互可以替换的,任意选择其中一个策略就能满足需求,而且是由客户端自己做出选择。而状态模式客户端只能选择初始节点,后续就会自动流转,各个状态是一个整体,不存在可以互相替换的状态。
- 最根本的差异在于策略模式是在求解同一个问题的多种解法,这些不同解法之间毫无关联;状态模式则不同,状态模式要求各个状态之间有所关联,以便实现状态转移。
区分这两个模式的关键是看行为是由状态驱动还是由一组算法驱动
以上是关于状态模式---State的主要内容,如果未能解决你的问题,请参考以下文章