网站怎么放在服务器上,frontpage做的社交网站,建设网站建设安全培训平台,科技手抄报简单又漂亮文章目录 1 状态模式#xff08;State Pattern#xff09;1.1 介绍1.2 概述1.3 状态模式的结构1.4 状态模式的优缺点1.5 状态模式的使用场景 2 案例一2.1 需求2.2 代码实现#xff08;未使用状态模式#xff09;2.3 代码实现#xff08;状态模式#xff09; 3 案例二3.1 … 文章目录 1 状态模式State Pattern1.1 介绍1.2 概述1.3 状态模式的结构1.4 状态模式的优缺点1.5 状态模式的使用场景 2 案例一2.1 需求2.2 代码实现未使用状态模式2.3 代码实现状态模式 3 案例二3.1 需求3.2 代码实现 前言本文章为瑞_系列专栏之《23种设计模式》的状态模式篇。本文中的部分图和概念等资料来源于博主学习设计模式的相关网站《菜鸟教程 | 设计模式》和《黑马程序员Java设计模式详解》特此注明。本文中涉及到的软件设计模式的概念、背景、优点、分类、以及UML图的基本知识和设计模式的6大法则等知识建议阅读 《瑞_23种设计模式_概述》 本系列 - 设计模式 - 链接《瑞_23种设计模式_概述》 ⬇️本系列 - 创建型模式 - 链接 单例模式《瑞_23种设计模式_单例模式》 工厂模式《瑞_23种设计模式_工厂模式》 原型模式《瑞_23种设计模式_原型模式》 抽象工厂模式《瑞_23种设计模式_抽象工厂模式》 建造者模式《瑞_23种设计模式_建造者模式》 ⬇️本系列 - 结构型模式 - 链接 代理模式《瑞_23种设计模式_代理模式》 适配器模式《瑞_23种设计模式_适配器模式》 装饰者模式《瑞_23种设计模式_装饰者模式》 桥接模式《瑞_23种设计模式_桥接模式》 外观模式《瑞_23种设计模式_外观模式》 组合模式《瑞_23种设计模式_组合模式》 享元模式《瑞_23种设计模式_享元模式》 ⬇️本系列 - 行为型模式 - 链接 模板方法模式《瑞_23种设计模式_模板方法模式》 策略模式《瑞_23种设计模式_策略模式》 命令模式《瑞_23种设计模式_命令模式》 职责链模式《瑞_23种设计模式_职责链模式》 状态模式《后续更新》 观察者模式《后续更新》 中介者模式《后续更新》 迭代器模式《后续更新》 访问者模式《后续更新》 备忘录模式《后续更新》 解释器模式《后续更新》 1 状态模式State Pattern 瑞状态模式堆程序员水平要求较高使用有点困难属于提升模式。可用于简化复杂的条件语句如一个操作中含有庞大的分支结构即长的 if-else 链或 switch case并且这些分支决定于对象的状态。 在状态模式State Pattern中类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。 瑞行为型模式用于描述程序在运行时复杂的流程控制即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务它涉及算法与对象间职责的分配。 瑞行为型模式分为类行为模式和对象行为模式前者采用继承机制来在类间分派行为后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低满足“合成复用原则”所以对象行为模式比类行为模式具有更大的灵活性。 状态模式属于对象行为模式 在状态模式中我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。
1.1 介绍 意图允许对象在内部状态发生改变时改变它的行为对象看起来好像修改了它的类。 主要解决对象的行为依赖于它的状态属性并且可以根据它的状态改变而改变它的相关行为。 何时使用代码中包含大量与对象状态有关的条件语句。 如何解决将各种具体的状态类抽象出来。 关键代码通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且状态模式的实现类的方法一般返回值或者是改变实例变量的值。也就是说状态模式一般和对象的状态有关。实现类的方法有不同的功能覆盖接口中的方法。状态模式和策略模式一样也可以用于消除 if…else 等条件选择语句。 应用实例 1️⃣ 打篮球的时候运动员可以有正常状态、不正常状态和超常状态。 2️⃣ 曾侯乙编钟中“钟是抽象接口”“钟A”等是具体状态“曾侯乙编钟”是具体环境Context。 优点 1️⃣ 封装了转换规则。 2️⃣枚举可能的状态在枚举状态之前需要确定状态种类。 3️⃣ 将所有与某个状态有关的行为放到一个类中并且可以方便地增加新的状态只需要改变对象状态即可改变对象的行为。 4️⃣ 允许状态转换逻辑与状态对象合成一体而不是某一个巨大的条件语句块。 5️⃣ 可以让多个环境对象共享一个状态对象从而减少系统中对象的个数。 缺点 1️⃣ 状态模式的使用必然会增加系统类和对象的个数。 2️⃣ 状态模式的结构与实现都较为复杂如果使用不当将导致程序结构和代码的混乱。 3️⃣ 状态模式对开闭原则的支持并不太好对于可以切换状态的状态模式增加新的状态类需要修改那些负责状态转换的源代码否则无法切换到新增状态而且修改某个状态类的行为也需修改对应类的源代码。 使用场景 1️⃣ 行为随状态改变而改变的场景。 2️⃣ 条件、分支语句的代替者。 注意事项在行为受状态约束的时候使用状态模式而且状态不超过 5 个。
1.2 概述 定义对有状态的对象把复杂的“判断逻辑”提取到不同的状态对象中允许状态对象在其内部状态发生改变时改变其行为。 状态模式通过将每个状态的行为封装在各自的类中使得对象可以在运行时根据其内部状态的变化而改变行为从而提供了一种优雅的方式来组织和管理复杂的状态转换逻辑。 使用状态模式的好处是可以简化复杂的条件语句如长的 if-else 链使得代码更加清晰和易于维护。此外当新的状态需要添加到系统中时只需要增加一个新的具体状态类而不需要修改环境类或其他状态类这有助于保持系统的灵活性和可扩展性。
1.3 状态模式的结构
状态模式主要包含以下角色: 1️⃣ 环境Context角色也称为上下文它定义了客户程序需要的接口维护一个当前状态并将与状态相关的操作委托给当前状态对象来处理。 2️⃣ 抽象状态State角色定义一个接口用以封装环境对象中的特定状态所对应的行为。 3️⃣ 具体状态Concrete State角色实现抽象状态所对应的行为。
1.4 状态模式的优缺点
优点
将所有与某个状态有关的行为放到一个类中并且可以方便地增加新的状态只需要改变对象状态即可改变对象的行为。允许状态转换逻辑与状态对象合成一体而不是某一个巨大的条件语句块。
缺点
状态模式的使用必然会增加系统类和对象的个数。状态模式的结构与实现都较为复杂如果使用不当将导致程序结构和代码的混乱。状态模式对开闭原则的支持并不太好。
1.5 状态模式的使用场景
当一个对象的行为取决于它的状态并且它必须在运行时根据状态改变它的行为时就可以考虑使用状态模式。一个操作中含有庞大的分支结构并且这些分支决定于对象的状态时。 2 案例一 【案例】电梯状态控制 2.1 需求 通过按钮来控制一个电梯的状态一个电梯有开门状态关门状态停止状态运行状态。每一种状态改变都有可能要根据其他状态来更新处理。例如如果电梯门现在处于运行时状态就不能进行开门操作而如果电梯门是停止状态就可以执行开门操作。 该案例未使用状态模式设计的类图如下 图为未使用状态模式前 2.2 代码实现未使用状态模式
电梯接口接口 /*** 电梯接口** author LiaoYuXing-Ray**/
public interface ILift {// 定义四个电梯状态的常量int OPENING_STATE 1;int CLOSING_STATE 2;int RUNNING_STATE 3;int STOPPING_STATE 4;// 设置电梯状态的功能void setState(int state);// 电梯操作功能void open();void close();void run();void stop();
}电梯类类 /*** 电梯类(ILift的子实现类)** author LiaoYuXing-Ray**/
public class Lift implements ILift {// 声明一个记录当前电梯的状态private int state;public void setState(int state) {this.state state;}public void open() {switch (state) { // 当前电梯状态case OPENING_STATE :// 什么事都不做break;case CLOSING_STATE :System.out.println(电梯打开了...);// 设置当前电梯状态为开启状态setState(OPENING_STATE);break;case STOPPING_STATE :System.out.println(电梯打开了...);// 设置当前电梯状态为开启状态setState(OPENING_STATE);break;case RUNNING_STATE :// 什么事都不做break;}}public void close() {switch (this.state) {case OPENING_STATE:System.out.println(电梯关门了。。。); // 只有开门状态可以关闭电梯门可以对应电梯状态表来看this.setState(CLOSING_STATE); // 关门之后电梯就是关闭状态了break;case CLOSING_STATE:// do nothing // 已经是关门状态不能关门break;case RUNNING_STATE:// do nothing // 运行时电梯门是关着的不能关门break;case STOPPING_STATE:// do nothing // 停止时电梯也是关着的不能关门break;}}public void run() {switch (this.state) {case OPENING_STATE: // 电梯不能开着门就走// do nothingbreak;case CLOSING_STATE: // 门关了可以运行了System.out.println(电梯开始运行了。。。);this.setState(RUNNING_STATE); // 现在是运行状态break;case RUNNING_STATE:// do nothing 已经是运行状态了break;case STOPPING_STATE:System.out.println(电梯开始运行了。。。);this.setState(RUNNING_STATE);break;}}public void stop() {switch (this.state) {case OPENING_STATE: // 开门的电梯已经是是停止的了(正常情况下)// do nothing break;case CLOSING_STATE: // 关门时才可以停止System.out.println(电梯停止了。。。);this.setState(STOPPING_STATE);break;case RUNNING_STATE: // 运行时当然可以停止了System.out.println(电梯停止了。。。);this.setState(STOPPING_STATE);break;case STOPPING_STATE:// do nothingbreak;}}
}
测试类 /*** 测试类** author LiaoYuXing-Ray**/
public class Client {public static void main(String[] args) {// 创建电梯对象Lift lift new Lift();/*设置当前电梯的状态*/lift.setState(ILift.OPENING_STATE);lift.open();lift.close();lift.run();lift.stop();System.out.println(\n 我是一条华丽的分割线 \n);lift.setState(ILift.CLOSING_STATE);lift.open();lift.close();lift.run();lift.stop();System.out.println(\n 我是一条华丽的分割线 \n);lift.setState(ILift.RUNNING_STATE);lift.open();lift.close();lift.run();lift.stop();System.out.println(\n 我是一条华丽的分割线 \n);lift.setState(ILift.STOPPING_STATE);lift.open();lift.close();lift.run();lift.stop();}
} 代码运行结果如下 电梯关门了。。。电梯开始运行了。。。电梯停止了。。。 我是一条华丽的分割线 电梯打开了...电梯关门了。。。电梯开始运行了。。。电梯停止了。。。 我是一条华丽的分割线 电梯停止了。。。 我是一条华丽的分割线 电梯打开了...电梯关门了。。。电梯开始运行了。。。电梯停止了。。。问题分析
使用了大量的switch…case这样的判断if…else也是一样)使程序的可阅读性变差。扩展性很差。如果新加了断电的状态我们需要修改上面判断逻辑
2.3 代码实现状态模式 对上述电梯的案例使用状态模式进行改进。类图如下 抽象状态类抽象类 /*** 抽象状态类** author LiaoYuXing-Ray**/
public abstract class LiftState {// 声明环境角色类变量protected Context context;public void setContext(Context context) {this.context context;}// 电梯开启操作public abstract void open();// 电梯关闭操作public abstract void close();// 电梯运行操作public abstract void run();// 电梯停止操作public abstract void stop();
}电梯开启状态类类 /*** 电梯开启状态类** author LiaoYuXing-Ray**/
public class OpeningState extends LiftState {// 当前状态要执行的方法public void open() {System.out.println(电梯开启。。。);}public void close() {// 修改状态super.context.setLiftState(Context.CLOSING_STATE);// 调用当前状态中的context中的close方法super.context.close();}public void run() {// 什么都不做}public void stop() {// 什么都不做}
}
电梯运行状态类类 /*** 电梯运行状态类** author LiaoYuXing-Ray**/
public class RunningState extends LiftState {// 运行的时候开电梯门你疯了电梯不会给你开的Overridepublic void open() {// do nothing}// 电梯门关闭这是肯定了Overridepublic void close() {// 虽然可以关门但这个动作不归我执行// do nothing}// 这是在运行状态下要实现的方法Overridepublic void run() {System.out.println(电梯正在运行...);}// 这个事绝对是合理的光运行不停止还有谁敢做这个电梯估计只有上帝了Overridepublic void stop() {super.context.setLiftState(Context.STOPPING_STATE);super.context.stop();}
}
电梯停止状态类类 /*** 电梯停止状态类** author LiaoYuXing-Ray**/
public class StoppingState extends LiftState {// 停止状态开门那是要的Overridepublic void open() {// 状态修改super.context.setLiftState(Context.OPENING_STATE);// 动作委托为CloseState来执行也就是委托给了ClosingState子类执行这个动作super.context.getLiftState().open();}// 虽然可以关门但这个动作不归我执行Overridepublic void close() {// 状态修改super.context.setLiftState(Context.CLOSING_STATE);// 动作委托为CloseState来执行也就是委托给了ClosingState子类执行这个动作super.context.getLiftState().close();}// 停止状态再跑起来正常的很Overridepublic void run() {// 状态修改super.context.setLiftState(Context.RUNNING_STATE);// 动作委托为CloseState来执行也就是委托给了ClosingState子类执行这个动作super.context.getLiftState().run();}// 停止状态是怎么发生的呢当然是停止方法执行了Overridepublic void stop() {System.out.println(电梯停止了...);}
}
电梯关闭状态类类 /*** 电梯关闭状态类** author LiaoYuXing-Ray**/
public class ClosingState extends LiftState {// 电梯门关闭这是关闭状态要实现的动作Overridepublic void close() {System.out.println(电梯门关闭...);}// 电梯门关了再打开Overridepublic void open() {super.context.setLiftState(Context.OPENING_STATE);super.context.open();}// 电梯门关了就跑这是再正常不过了Overridepublic void run() {super.context.setLiftState(Context.RUNNING_STATE);super.context.run();}// 电梯门关着我就不按楼层Overridepublic void stop() {super.context.setLiftState(Context.STOPPING_STATE);super.context.stop();}
}环境角色类类 /*** 环境角色类** author LiaoYuXing-Ray**/
public class Context {// 定义对应状态对象的常量public final static OpeningState OPENING_STATE new OpeningState();public final static ClosingState CLOSING_STATE new ClosingState();public final static RunningState RUNNING_STATE new RunningState();public final static StoppingState STOPPING_STATE new StoppingState();// 定义一个当前电梯状态变量private LiftState liftState;public LiftState getLiftState() {return liftState;}// 设置当前状态对象public void setLiftState(LiftState liftState) {this.liftState liftState;// 设置当前状态对象中的Context对象this.liftState.setContext(this);}public void open() {this.liftState.open();}public void close() {this.liftState.close();}public void run() {this.liftState.run();}public void stop() {this.liftState.stop();}
}测试类 /*** 测试类** author LiaoYuXing-Ray**/
public class Client {public static void main(String[] args) {// 创建环境角色对象Context context new Context();/*设置当前电梯装填*/context.setLiftState(new OpeningState());context.open();context.run();context.close();context.stop();System.out.println(\n 我是一条华丽的分割线 \n);context.setLiftState(new RunningState());context.open();context.run();context.close();context.stop();System.out.println(\n 我是一条华丽的分割线 \n);context.setLiftState(new StoppingState());context.open();context.run();context.close();context.stop();System.out.println(\n 我是一条华丽的分割线 \n);context.setLiftState(new ClosingState());context.open();context.run();context.close();context.stop();}
} 代码运行结果如下 电梯开启。。。电梯门关闭...电梯停止了... 我是一条华丽的分割线 电梯正在运行...电梯停止了... 我是一条华丽的分割线 电梯开启。。。电梯门关闭...电梯停止了... 我是一条华丽的分割线 电梯开启。。。电梯门关闭...电梯停止了...3 案例二 本案例为菜鸟教程中的案例 3.1 需求 我们将创建一个 State 接口和实现了 State 接口的实体状态类。Context 是一个带有某个状态的类。StatePatternDemo我们的演示类使用 Context 和状态对象来演示 Context 在状态改变时的行为变化。 3.2 代码实现
步骤 1 创建一个接口。
State.java public interface State {public void doAction(Context context);
}步骤 2 创建实现接口的实体类。
StartState.java public class StartState implements State {public void doAction(Context context) {System.out.println(Player is in start state);context.setState(this); }public String toString(){return Start State;}
}StopState.java public class StopState implements State {public void doAction(Context context) {System.out.println(Player is in stop state);context.setState(this); }public String toString(){return Stop State;}
}步骤 3 创建 Context 类。
Context.java public class Context {private State state;public Context(){state null;}public void setState(State state){this.state state; }public State getState(){return state;}
}步骤 4 使用 Context 来查看当状态 State 改变时的行为变化。
StatePatternDemo.java public class StatePatternDemo {public static void main(String[] args) {Context context new Context();StartState startState new StartState();startState.doAction(context);System.out.println(context.getState().toString());StopState stopState new StopState();stopState.doAction(context);System.out.println(context.getState().toString());}
}步骤 5 执行程序输出结果 Player is in start stateStart StatePlayer is in stop stateStop State本文是博主的粗浅理解可能存在一些错误或不完善之处如有遗漏或错误欢迎各位补充谢谢 如果觉得这篇文章对您有所帮助的话请动动小手点波关注你的点赞收藏⭐️转发评论都是对博主最好的支持~