行为型模式--状态模式

news/2024/10/18 0:18:59/

目录

举例

状态模式

定义

结构

 代码实现

优缺点

优点:

缺点:

使用场景

举例

【例】通过按钮来控制一个电梯的状态,一个电梯有开门状态,关门状态,停止状态,运行状态。每一 种状态改变,都有可能要根据其他状态来更新处理。例如,如果电梯门现在处于运行时状态,就不能进 行开门操作,而如果电梯门是停止状态,就可以执行开门操作。

类图如下:

问题分析:

比如其中的open方法:

//执行开门动作
@Override
public void open() {switch (this.state) {case OPENING_STATE://门已经开了,不能再开门了//do nothingbreak;case CLOSING_STATE://关门状态,门打开:System.out.println("电梯门打开了。。。");this.setState(OPENING_STATE);break;case RUNNING_STATE://do nothing 运行时电梯不能开门break;case STOPPING_STATE:System.out.println("电梯门开了。。。");//电梯停了,可以开门了this.setState(OPENING_STATE);break;}
}

使用了大量的switch…case这样的判断(if…else也是一样),使程序的可阅读性变差。 扩展性很差。如果新加了断电的状态,我们需要修改上面判断逻辑。这个时候就需要用到状态模式

状态模式

定义

对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变 时改变其行为。

结构

状态模式包含以下主要角色。

环境(Context)角色:也称为上下文,它定义了客户程序需要的接口,维护一个当前状态,并 将与状态相关的操作委托给当前状态对象来处理。

抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为。

具体状态(Concrete State)角色:实现抽象状态所对应的行为。

 代码实现

抽象状态类

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();
}

具体状态类:

开启状态:

//开启状态
public class OpenningState extends LiftState {//开启当然可以关闭了,我就想测试一下电梯门开关功能@Overridepublic void open() {System.out.println("电梯门开启...");}@Overridepublic void close() {//状态修改super.context.setLiftState(Context.closeingState);//动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作super.context.getLiftState().close();}//电梯门不能开着就跑,这里什么也不做@Overridepublic void run() {//do nothing}//开门状态已经是停止的了@Overridepublic void stop() {//do nothing}
}

运行状态:

//运行状态
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.stoppingState);super.context.stop();}
}

停止状态:

//停止状态
public class StoppingState extends LiftState {//停止状态,开门,那是要的!@Overridepublic void open() {//状态修改super.context.setLiftState(Context.openningState);//动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作super.context.getLiftState().open();}@Overridepublic void close() {//虽然可以关门,但这个动作不归我执行//状态修改super.context.setLiftState(Context.closeingState);//动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作super.context.getLiftState().close();}//停止状态再跑起来,正常的很@Overridepublic void run() {//状态修改super.context.setLiftState(Context.runningState);//动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作super.context.getLiftState().run();}//停止状态是怎么发生的呢?当然是停止方法执行了@Overridepublic void stop() {System.out.println("电梯停止了...");}
}

关闭状态:

//关闭状态
public class ClosingState extends LiftState {@Override//电梯门关闭,这是关闭状态要实现的动作public void close() {System.out.println("电梯门关闭...");}//电梯门关了再打开,逗你玩呢,那这个允许呀@Overridepublic void open() {super.context.setLiftState(Context.openningState);super.context.open();}//电梯门关了就跑,这是再正常不过了@Overridepublic void run() {super.context.setLiftState(Context.runningState);super.context.run();}//电梯门关着,我就不按楼层@Overridepublic void stop() {super.context.setLiftState(Context.stoppingState);super.context.stop();}
}

环境角色:

public class Context {//定义出所有的电梯状态//开门状态,这时候电梯只能关闭public final static OpenningState openningState = newOpenningState();//关闭状态,这时候电梯可以运行、停止和开门public final static ClosingState closeingState = new ClosingState();//运行状态,这时候电梯只能停止public final static RunningState runningState = new RunningState();//停止状态,这时候电梯可以开门、运行public final static StoppingState stoppingState = newStoppingState();//定义一个当前电梯状态private LiftState liftState;public LiftState getLiftState() {return this.liftState;}public void setLiftState(LiftState liftState) {//当前环境改变this.liftState = liftState;//把当前的环境通知到各个实现类中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();}
}

测试类:

//测试类
public class Client {public static void main(String[] args) {Context context = new Context();context.setLiftState(new ClosingState());context.open();context.close();context.run();context.stop();}
}

优缺点

优点:

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

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

缺点:

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

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

状态模式对"开闭原则"的支持并不太好。

使用场景

当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使 用状态模式。

一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。


http://www.ppmy.cn/news/533334.html

相关文章

剑指 Offer 55 - II. 平衡二叉树 / LeetCode 110. 平衡二叉树(二叉树后序遍历)

题目: 链接:剑指 Offer 55 - II. 平衡二叉树;LeetCode 110. 平衡二叉树 难度:简单 给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个节点 …

MySQL权限控制及日志管理

MySQL权限控制及日志管理 用户权限管理 创建用户 CREATE USER 用户名IP地址 [ IDENTIFIED BY 密码 ];GRANT SELECT ON *.* TO 用户名’IP地址’ IDENTIFIED BY "密码";--创建一个用户名为Usr1 密码为 Usr1.mysql的用户 并授权 CREATE USER…

【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 文章目录 系列文章目录前言一、所有权(Ownership)1.1.、所有权(Ow…

【JUC(一)】进程、线程与管程

1 进程 1.1 概述 进程:程序是静止的,进程实体的运行过程就是进程,是系统进行资源分配的基本单位 进程的特征:并发性、异步性、动态性、独立性、结构性 线程:线程是属于进程的,是一个基本的 CPU 执行单元…

【windows10】查看计算机的WIFI密码

【windows10】查看计算机的WIFI密码 1、背景2、操作 1、背景 无线路由器设置完密码后,经常会忘记。 当有新的设备需要接入网络的时候,如何能快速获得wifi密码呢? 本博客分享一种通过已联网的计算机来查看wifi密码。 2、操作 -step-2.1、打…

【软件工程】测试九

文章目录 单选题判断题填空题 单选题 软件维护的副作用,是指()。 A. 因修改软件而造成的错误 B. 开发时的错误 C. 隐含的错误 D. 运行时误操作 正确答案: A 为了适应软硬件环境变化而修改软件的过程是( )。 A. 适应性维护 B. 校正性维护 C. 完善性维护 …

在Linux上卸载和重新安装NVM

NVM(Node Version Manager)是一个方便的工具,用于在同一台机器上管理和切换不同版本的Node.js。有时候,我们可能需要卸载NVM并重新安装它,以解决一些问题或进行更新。在本篇博客中,我们将提供在Linux上卸载…

VMware虚拟机黑屏死机解决方法

1.问题:虚拟机开机右一个centos出现黑屏,而其他的centos是正常的。 2.解决步骤: 1)在Windows系统下的命令符窗口(cmd),以系统管理员的身份进入。 2)输入“netsh winsock reset”,如果出现成功…