设计模式-状态模式
状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类
通俗解释:改变一个状态值时,其行为发生了改变。行为也就是做了什么。
下面一个例子:(大话设计模式的例子)
一天之中的工作状态随着时间改变
早晨-精神百倍
中午-犯困
下午-状态不错
(完成工作的情况)
傍晚-下班
(没完成工作的情况)
傍晚-没完成工作-加班
晚上-困得要死
结合这个例子,编写代码
@Data public class Work { private Integer hour; private Integer finish = 0; //默认工作没有完成 public void writeProgram(){ if (hour < 12){ System.out.println("当前时间:"+hour+"点,上午工作,精神百倍"); }else if (hour < 13){ System.out.println("当前时间:"+hour+"点,饿了,午饭,犯困"); }else if (hour < 17){ System.out.println("当前时间:"+hour+"点,下午状态不错,继续努力"); }else { if (finish == 1){ System.out.println("当前时间:"+hour+"点,工作完成,下班回家"); }else { if (hour < 21){ System.out.println("当前时间:"+hour+"点,加班,疲累至极"); }else { System.out.println("当前时间:"+hour+"点,不行了,睡着了"); } } } } }
测试
public class WorkTest { public static void main(String[] args) { Work work = new Work(); work.setHour(8); work.writeProgram(); work.setHour(11); work.writeProgram(); work.setHour(13); work.writeProgram(); work.setHour(17); work.setFinish(1); work.writeProgram(); work.setHour(18); work.writeProgram(); work.setHour(20); work.writeProgram(); work.setHour(22); work.writeProgram(); } }
例子中一直都是针对hour来进行判断,不同的时间点输出不同的内容
但是这样来看过多的if...else,代码过于凌乱,后期肯定不好维护
此时这种情况就可以用状态模式
State:抽象状态类,定义一个接口以封装与Context的一个特定状态的行为
ConcreteState类,具体状态的类,每个子类实现一个状态的行为
Context类,维护一个ConcreteState子类的实例,这个实例定义当前的状态
按照UML类图来改造代码
1.创建Status类,定义每种状态下的行为
abstract class Status { //为什么要加一个Work的入参,需要 具体状态类来负责状态之间的转换 //状态转换也可以放到Context类来做 public abstract void workHandle(Work work); }
2.创建Context类 重点是其中的Status的引用,这里我默认了status是早晨的状态
/** * Context类 * @author wrj * @description * @Date 2021/12/13 2:03 下午 */ @Data public class Work { private Integer hour; private Integer finish = 0; private Status status = new MorningWorkStatus(); public void writeProgram(){ status.workHandle(this); } }
3.创建ConcreteStatus类
/** * 早晨的工作状态 * @author wrj * @description * @Date 2021/12/13 3:08 下午 */ public class MorningWorkStatus extends Status{ @Override public void workHandle(Work work) { if (work.getHour() < 12){ System.out.println("当前时间:"+work.getHour()+"点,上午工作,精神百倍"); }else { //条件不满足的情况下设置为中午的工作状态 work.setStatus(new NoonWorkStatus()); work.writeProgram(); } } }
/** * 中午工作状态 * @author wrj * @description * @Date 2021/12/13 3:08 下午 */ public class NoonWorkStatus extends Status{ @Override public void workHandle(Work work) { if (work.getHour() < 12){ System.out.println("当前时间:"+work.getHour()+"点,饿了,午饭,犯困"); }else { //条件不满足的情况下设置为下午的工作状态 work.setStatus(new AfterNoonWorkStatus()); work.writeProgram(); } } }
/** * 下午的工作状态 * @author wrj * @description * @Date 2021/12/13 3:08 下午 */ public class AfterNoonWorkStatus extends Status{ @Override public void workHandle(Work work) { if (work.getHour() <= 17){ System.out.println("当前时间:"+work.getHour()+"点,下午状态不错,继续努力"); }else { work.setStatus(new EveningWorkStatus()); work.writeProgram(); } } }
/** * 傍晚的工作状态 * @author wrj * @description * @Date 2021/12/13 3:20 下午 */ public class EveningWorkStatus extends Status{ @Override public void workHandle(Work work) { if (work.getFinish() == 1){ work.setStatus(new FinishWorkStatus()); work.writeProgram(); }else { if (work.getHour() < 20){ System.out.println("当前时间:"+work.getHour()+"点,加班,疲累至极"); }else { work.setStatus(new SleepingWorkStatus()); work.writeProgram(); } } } }
/** * 晚上快要睡着的工作状态 * @author wrj * @description * @Date 2021/12/13 3:29 下午 */ public class SleepingWorkStatus extends Status{ @Override public void workHandle(Work work) { System.out.println("当前时间:"+work.getHour()+"点,不行了,睡着了"); } }
4.测试类
public class Test { public static void main(String[] args) { Work work = new Work(); work.setHour(8); work.writeProgram(); work.setHour(11); work.writeProgram(); work.setHour(13); work.writeProgram(); work.setHour(17); work.setFinish(0); work.writeProgram(); work.setHour(18); work.writeProgram(); work.setHour(20); work.writeProgram(); work.setHour(22); work.writeProgram(); } }
大话设计模式中是这么说的:
将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换
将每个状态需要做的事情封装在一个类中,不同的状态对应不同的类,对应不同的行为。当需要增加新的状态时,可以通过创建新的类来增加新的状态和行为。
上面例子中的状态转换是在具体的类中,也可以放到Context中来做,(思路:通过判断当前status的具体类型,然后赋值为下一个阶段的具体类型),然后具体的子类调用ConcreteState
使用状态模式这样做的好处是,假如公司决定晚上8点强制下班,那么只需要增加一个强制下班的子类,然后改变EveningWorkStatus的work.setStatus(new SleepingWorkStatus());将new SleepingWorkStatus()改为新创建的强制下班的子类,无须改动其他的子类。
在原有的代码上做小小的改动即可满足。但是缺点是会有很多类,容易类爆炸,推荐在状态类型不多的情况下使用状态模式