设计模式之----状态模式(State-pattern)的理解

本文探讨了状态模式在编程中的应用,如何通过将状态和行为分离,避免冗余if-else,提升代码可读性和扩展性。通过实例解析鼠标交互元素状态变化,展示了如何创建抽象状态、具体状态及状态工厂来管理不同状态的切换。

1.前言

在现实生活中,人都有高兴和伤心的时候,不同的时候有不同的行为,有状态的对象编程中高兴,伤心可以看成一种状态,传统的解决方案是:人的不同时候的行为都要考虑到的话,然后使用 if-else 或 switch-case 语句来做状态判断,再进行不同情况的处理。这样代码会会过于臃肿,可读性差,且不具备扩展性,维护难度也大。且增加新的状态时要添加新的 if-else 语句,这违背了“开闭原则”,不利于程序的扩展。


2.概念

状态模式的定义:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。状态模式的思想是:当控制一个对象状态转换的条件表达式过于复杂时,把相关“判断逻辑”提取出来,用各个不同的类进行表示,系统处于哪种情况,直接使用相应的状态类对象进行处理,这样能把原来复杂的逻辑判断简单化,消除了 if-else、switch-case 等冗余语句,代码更有层次性,并且具备良好的扩展力。


3.模式的结构和实现

状态模式把受环境改变的对象行为包装在不同的状态对象里,其目的是让一个对象在其内部状态改变的时候,其行为也随之改变。现在我们来分析其基本结构和实现方法。

3.1 模式的结构

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

  1. 环境类(Context)角色:也称为上下文,相当是所有状态的管理者(manage)并负责具体状态的切换。
  2. 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
  3. 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。

3.2模式的实现

场景:这个场景大家都很熟悉,鼠标进去某个元素,会有个高亮的样式,当鼠标点击这个元素的时候,会有个选中的样式,再次点击选中状态样式消失,当鼠标离开元素,元素没有样式

在这里插入图片描述
简单分析下,这里的话会有4个状态,正常状态(无样式),高亮状态(悬浮样式),选中状态(选中样式),高亮选中状态(悬浮加选中样式),并且一个状态进入另一个状态是有条件的,看下图

在这里插入图片描述
按需求画出类图

在这里插入图片描述
1.首先创建一个抽象类ElementStatus

export abstract class ElementStatus {
    public statusName: string;
    public abstract calculateState(eventName: string):ElementStatus;
}

2.分别创建ElementNormalState类(正常状态),ElementHightLightState类(高亮状态),ElementHightLightSelectState类(高亮选中状态),ElementSelectState类(选中状态)和构建这些状态的StateFactory类(工厂)

//ElementNormalState.ts     正常状态
import { ElementStatus } from "./ElementStatus";
import { StateFactory } from "./StateFactory";
export class ElementNormalState extends ElementStatus {
    public statusName: string;
    constructor() {
        super();
        this.statusName = "正常状态";
    }

    public calculateState(eventName: string):ElementStatus {
        if (eventName == "mouseEnter") {
            return StateFactory.getElementStatus("ElementHightLightState");
        }
        throw new Error("现在是正常状态,切换不了其他状态");
    }
}

//ElementHightLightState.ts  高亮状态
import { ElementStatus } from "./ElementStatus";
import { StateFactory } from "./StateFactory";
export class ElementHightLightState extends ElementStatus {
    public statusName: string;
    constructor() {
        super();
        this.statusName = "高亮状态";
    }
    public calculateState(eventName: string): ElementStatus {
        if (eventName == "mouseLeaver") {
            return StateFactory.getElementStatus("ElementNormalState");
        } else if (eventName == "mouseClick") {
            return StateFactory.getElementStatus("ElementHightLightSelectState");
        }
        throw new Error("现在是高亮状态,切换不了其他状态");
    }
}


//ElementHightLightSelectState.ts  高亮选中状态
import { ElementStatus } from "./ElementStatus";
import { StateFactory } from "./StateFactory";
export class ElementHightLightSelectState extends ElementStatus {
    public statusName: string;
    constructor() {
        super();
        this.statusName = "高亮选中状态";
    }
    public calculateState(eventName: string): ElementStatus {
        if (eventName == "mouseLeaver") {
            return StateFactory.getElementStatus("ElementSelectState");
        } else if (eventName == "mouseClick") {
            return StateFactory.getElementStatus("ElementHightLightState");
        }
        throw new Error("现在是高亮选中状态,切换不了其他状态")
    }
}


//ElementSelectState.ts 选中状态
import { ElementStatus } from "./ElementStatus";
import { StateFactory } from "./StateFactory";

export class ElementSelectState extends ElementStatus {
    public statusName: string;
    constructor() {
        super();
        this.statusName = "选中状态";
    }
    public calculateState(eventName: string): ElementStatus {
        if (eventName == "mouseEnter") {
            return StateFactory.getElementStatus("ElementHightLightSelectState");
        }
        throw new Error("现在是选中状态,切换不了其他状态");
    }
}


//StateFactory.ts    工厂类
import { ElementHightLightSelectState } from "./ElementHightLightSelectState";
import { ElementHightLightState } from "./ElementHightLightState";
import { ElementNormalState } from "./ElementNormalState";
import { ElementSelectState } from "./ElementSelectState";
export class StateFactory {
    public static getElementStatus(statusName: string): Status.ElementStatus {
        switch (statusName) {
            case "ElementNormalState":
                return new ElementNormalState();
            case "ElementHightLightState":
                return new ElementHightLightState();
            case "ElementHightLightSelectState":
                return new ElementHightLightSelectState();
            case "ElementSelectState":
                return new ElementSelectState();
            default:
                return new ElementNormalState();
        }
    }
}


3.创建ElementStatusContext类 管理这些状态的类,设置默认状态是正常状态

//ElementStatusContext.ts
import { ElementNormalState } from "./ElementNormalState";
export class ElementStatusContext{
    public currentStatus: Status.ElementStatus;

    constructor() {
        this.currentStatus = new ElementNormalState();
    }

    public getStatus() {
        return this.currentStatus
    }

    public setStatus(status: Status.ElementStatus) {
        this.currentStatus = status;
    }

    public changeStatus(eventName: string): Status.ElementStatus {
        return this.currentStatus.calculateState(eventName);
    }

}

//Status.d.ts   ts声明文件
declare namespace Status {
    export type ElementStatus =import ("./ElementStatus").ElementStatus;
    export type ElementStatusContext =import ("./ElementStatusContext").ElementStatusContext;

}

4.最后IndexController 通过事件绑定好这些状态并显示在UI界面上

//Index.controller.ts
import angular from "angular";
import { ElementStatusContext } from "./ElementStatusContext";
export class IndexController implements angular.IController {
    public static ElementStatusContext: Status.ElementStatusContext;
    public statusName: string;
    constructor() {
        IndexController.ElementStatusContext = new ElementStatusContext();
        this.statusName = IndexController.ElementStatusContext.getStatus().statusName;
    }

    //鼠标进入事件
    public mouseEnterEvent(): void {
        let status = this.calAndSetStatus(IndexController.ElementStatusContext, "mouseEnter");
        this.statusName = status.statusName

    }

    //鼠标离开事件
    public mouseLeaveEvent(): void {
        let status = this.calAndSetStatus(IndexController.ElementStatusContext, "mouseLeaver");
        this.statusName = status.statusName
    }

    //colorElement点击事件
    public colorElementClickEvent(): void {
        let status = this.calAndSetStatus(IndexController.ElementStatusContext, "mouseClick");
        this.statusName = status.statusName
    }


    //计算并设置状态
    private calAndSetStatus(StatusContext: Status.ElementStatusContext, eventName: string) {
        let status = StatusContext.changeStatus(eventName);
        StatusContext.setStatus(status);
        return status;
    }
}

下面是 index.html ui界面

<!DOCTYPE html>
<html lang="en" ng-app="myApp">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    .element {
        width: 200px;
        height: 200px;
        border: 5px solid  #ccc;
        margin: 0 auto;
        line-height: 200px;
        text-align: center;
        font-size: 20px;
    }

    .hight-light {
        background-color: greenyellow;
    }

    .select {
       border-color: green;
    }

    .hight-light-select {
        background-color: greenyellow;
        border-color: green;
    }
</style>

<body ng-controller="IndexController as vm">
    <div class="element" ng-mouseenter="vm.mouseEnterEvent()" ng-mouseleave="vm.mouseLeaveEvent()"
        ng-click="vm.colorElementClickEvent()" ng-class="{'hight-light':vm.statusName=='高亮状态','select':vm.statusName=='选中状态','hight-light-select':vm.statusName=='高亮选中状态'}">{{vm.statusName}}</div>
</body>
</html>

最后看下效果图:

在这里插入图片描述

总结优缺点

优点:

  1. 结构清晰,状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
  2. 将状态转换显示化,减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
  3. 状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。

缺点:

  1. 状态模式的使用必然会增加系统的类与对象的个数。
  2. 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
  3. 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码。
### 升级 Ubuntu 20.04 LTS 到 24.04 LTS 的步骤 Ubuntu 系统的升级是按顺序进行的,因此必须首先将系统从 Ubuntu 20.04 LTS 升级Ubuntu 22.04 LTS。完成此步骤后,才能进一步升级Ubuntu 24.04 LTS [^1]。 #### 步骤一:升级Ubuntu 22.04 LTS 在执行任何升级之前,请确保备份重要数据以避免意外丢失。 1. 更新当前系统的软件包列表并安装所有可用更新: ```bash sudo apt update && sudo apt upgrade -y ``` 2. 安装 `update-manager-core` 包(如果尚未安装): ```bash sudo apt install update-manager-core ``` 3. 检查是否可以升级到下一个版本: ```bash sudo do-release-upgrade -c ``` 4. 如果确认可以升级,则执行实际的升级过程: ```bash sudo do-release-upgrade ``` 5. 按照屏幕上的提示完成升级过程,并重启计算机。 #### 步骤二:升级Ubuntu 24.04 LTS 一旦您已经成功升级到了 Ubuntu 22.04 LTS,接下来就可以继续升级Ubuntu 24.04 LTS。 1.Ubuntu 22.04 上重复第一步中的命令来更新和升级现有的软件包。 2. 使用以下命令检查是否有新的发行版可供升级: ```bash sudo do-release-upgrade -c ``` 3. 执行系统升级命令: ```bash sudo do-release-upgrade ``` 4. 遵循屏幕上的指示完成升级过程,并重新启动您的计算机。 ### 注意事项 - 在开始升级之前,建议清理不必要的软件包和缓存,以减少潜在的问题: ```bash sudo apt autoremove sudo apt clean ``` - 如果遇到问题提示没有可用的 LTS 开发版本,需要编辑 `/etc/update-manager/release-upgrades` 文件并将 `Prompt` 设置为 `normal` [^3]。 - 可以使用 `lsb_release -a` 命令来查看当前运行的 Ubuntu 版本 [^3]。 ### 示例代码 以下是用于更新和升级的基本命令汇总: ```bash # 更新软件包列表 sudo apt update # 升级已安装的软件包 sudo apt upgrade -y # 清理不再需要的软件包 sudo apt autoremove # 清除本地存储的软件包缓存 sudo apt clean # 检查是否存在新版本 sudo do-release-upgrade -c # 开始升级到新版本 sudo do-release-upgrade # 查看当前Ubuntu版本 lsb_release -a ``` 请根据实际情况调整这些命令,并仔细遵循升级过程中提供的指导。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值