设计模式(24)行为型模式 - 状态模式

前言

温故而知新

先复习前面学到的行为型模式:

  • 模板方法模式:定义一个算法流程骨架,特定的步骤延迟到子类实现(请客过程:点单-》吃-》买单 ,吃什么由子类决定)
  • 命令模式:将命令对象封装 ,聚合执行者,命令请求者调用命令对象即可完成命令(遥控器按钮就是各个命令,点击按钮即可完成开关灯)
  • 访问者模式:将施加与对象结构的元素上的操作分割封装成访问者,对象结构提供访问者访问的接口,即访问者改变不会改动对象结构(购物车是对象结构,内部存放许多商品元素,顾客可以查看商品质量,收银员可以查看商品价格)
  • 迭代器模式:将聚合对象的元素存储功能和遍历功能分隔,将遍历功能封装成迭代器,聚合对象通过工厂方法创建相对应的迭代器(Linux目录迭代器访问层级)
  • 观察者模式:定义对象间一对多的依赖关系,当对象状态改变时,自动通知所有依赖对象并更新对象数据(气象局天气数据改变,对应的APP中天气数据也改变)
  • 中介者模式:针对对象间复杂的网状关系,创建一个中介者封装一系列的对象交互,对象可以通过中介者间接访问任何对象,对象间无显式引用(QQ聊天不需要知道对方的IP地址,通过服务器通信)
  • 备忘录模式:定义一个备忘录角色存储对象的内部状态,提供给对象状态恢复的功能(游戏的存档读档功能)
  • 解释器模式:给分析对象定义一个语言和该语言的文法表示,再设计一个解释器解析语言中句子的语义(加减法解释器可以解释输入的表达式字符串)

接下来,学习状态模式


现实中的问题

先搞清楚,什么是状态?

一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态
这样的对象叫做有状态的对象

我们学习进程的时候,是不是就有5种基本状态
在这里插入图片描述

用面向对象的方法看待进程状态,可以有五个状态对象,每一个对象都有不同的方法

怎么去描述状态及状态间的改变,可以选择状态模式
(仅使用模式思想,并不是真的去实现状态改变)


状态模式

什么是状态模式?

状态模式(State Pattern) :允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式

状态模式的作用?

状态模式主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换

对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化

模式结构

在这里插入图片描述

模式角色:

  • 环境(Context)角色:也称为上下文,它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理
  • 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为
  • 具体状态(Concrete State)角色:实现抽象状态所对应的行为

模式具体实现

我们可以简单的用状态模式来描述上面的进程状态改变
在这里插入图片描述

package com.company.Behavioral.Status;

//环境类
class ThreadContext{
    private State state;
    public ThreadContext(){
        //初始状态是创建状态
        state = new Create();
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }
    //创建状态:开始运行进程
    public void start(){
        ((Create)state).start(this);
    }
    //就绪状态:进程调度
    public void contro(){
        ((Runnable)state).control(this);
    }
    //运行状态:阻塞
    public void block(){
        ((Running)state).block(this);
    }
    //运行状态:返回就绪
    public void consume(){
        ((Running)state).consume(this);
    }
    //运行状态:终结
    public void stop(){
        ((Running)state).stop(this);
    }
    //阻塞状态:就绪
    public void resume(){
        ((Blocked) state).resume(this);
    }
}

abstract class State {
    protected String stateName;
}

class Create extends State{
    public Create(){
        stateName = "新建状态";
        System.out.println("当前线程处于:"+stateName);
    }
    public void start(ThreadContext threadContext){
        System.out.println("=== 调用start()方法 ===");
        //只有新建状态才可以调用start方法进入 就绪状态
        if (stateName.equals("新建状态")){
            threadContext.setState(new Runnable());
        }
        else {
            System.out.println("当前不是新建状态, 不能调用start()方法");
        }
    }
}
//就绪状态
class Runnable extends State{
    public Runnable() {
        stateName = "就绪状态";
        System.out.println("当前线程处于:"+stateName);
    }
    //就绪状态进行进程调度
    public void control(ThreadContext threadContext){

        //只有就绪状态才可以 执行进程调度方法 进入 执行状态
        if (stateName.equals("就绪状态")){
            System.out.println("=== 进行进程调度 ===");
            threadContext.setState(new Running());
        }else {
            System.out.println("当前线程不是就绪状态,不能进行进程调度");
        }
    }
}
//运行状态
class Running extends State{
    public Running() {
        stateName = "运行状态";
        System.out.println("当前线程处于:"+stateName);
    }
    public void block(ThreadContext threadContext){
        //运行状态阻塞
        if (stateName.equals("运行状态")){
            System.out.println("=== 进程阻塞 ===");
            threadContext.setState(new Blocked());
        }else
        {
            System.out.println("当前线程不是阻塞状态,不能调用block()方法阻塞.");
        }
    }
    //时间片用完,返回就绪
    public void consume(ThreadContext threadContext){
        if (stateName.equals("运行状态")){
            System.out.println("=== 时间片使用完,返回就绪状态 ===");
            threadContext.setState(new Runnable());
        }else
        {
            System.out.println("当前线程不是运行状态,不能调用consume()方法");
        }
    }
    //运行完成,进入终止状态
    public void stop(ThreadContext threadContext){
        if (stateName.equals("运行状态")){
            System.out.println("=== 运行完成,进入终止状态 ===");
            threadContext.setState(new Dead());
        }else
        {
            System.out.println("当前线程不是运行状态,不能调用stop()方法");
        }
    }
}
//阻塞状态
class Blocked extends State{
    public Blocked() {
        stateName = "阻塞状态";
        System.out.println("当前线程处于:"+stateName);
    }
    public void resume(ThreadContext threadContext){
        if (stateName.equals("阻塞状态")){
            System.out.println("=== 阻塞状态就绪 ===");
            threadContext.setState(new Runnable());
        }else {
            System.out.println("当前线程不是阻塞状态,不能调用resume()方法.");
        }
    }
}
//死亡状态
class Dead extends State
{
    public Dead()
    {
        stateName="死亡状态";
        System.out.println("当前线程处于:"+stateName);
    }
}
//客户类
class  Client{
    public static void main(String[] args) {
        ThreadContext threadContext = new ThreadContext();
        threadContext.start();
        threadContext.contro();
        threadContext.block();
        threadContext.resume();
        threadContext.contro();
        threadContext.stop();
    }
}

在这里插入图片描述


模式优缺点

优点

  • 封装了转换规则,代码有很强的可读性
  • 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为,方便维护
  • 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块(例如if-else切换状态会显得很臃肿)
  • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数(联用享元模式)

缺点

  • 状态模式的使用必然会增加系统类和对象的个数
  • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱
  • 状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码

适用场景

  • 对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为
  • 代码中包含大量与对象状态有关的条件语句

状态模式就是用复杂度换耦合度,根据需求选择是否使用状态模式

模式扩展

  1. 与享元模式联用

如果有多个环境对象,就可以使用享元模式共享这些状态角色

  1. 状态模式在工作流或游戏等类型的软件中得以广泛使用,甚至可以用于这些系统的核心功能设计

使用状态模式可以描述工作流对象(如批文)的状态转换以及不同状态下它所具有的行为

  1. 简单状态模式与可切换状态模式

简单状态模式:是指状态都相互独立,状态之间无须进行转换的状态模式

可切换状态的状态模式:大多数的状态模式都是可以切换状态的状态模式,在实现状态切换时,在具体状态类内部需要调用环境类Context的setState()方法进行状态的转换操作

很明显,简单状态模式是符合开闭原则的,且耦合度低,但是不实用
可切换状态的状态模式就是案例中的模式


总结

  • 状态模式是允许一个对象在其状态改变时改变行为,对象看起来像是修改了类
  • 状态模式有3个角色:环境角色、抽象状态类、具体状态类
  • 环境角色维护一个抽象状态类的实例,这个实例定义当前状态,根据这个状态的变化改变行为;抽象状态类定义具体状态类的公共属性;具体状态类实现一个与环境类一个状态相关的行为,不同的状态行为有所不同
  • 状态模式的优点:封装了装换规则,改变对象状态即可改变行为;缺点:增加系统类和复杂度,可切换的状态模式不满足开闭原则
  • 状态模式适用于对象的行为依赖于它的状态并且可以根据它的状态改变而改变它的相关行为;代码中包含大量与对象状态有关的条件语句
  • 状态模式可以和享元模式联用,多个环境角色共享状态
  • 简单状态模式是与可切换的状态模式
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值