设计模式学习笔记(十七:状态模式)

舞动的心 舞动的心     2022-08-12     308

关键词:

1.1概述

    允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。这就是状态模式的定义。

    一个对象的状态依赖于它的变量的取值情况,对象在不同的运行环境中,可能具有不同的状态。在许多情况下,对象调用方法所产生的行为效果依赖于它当时的状态。

  例如,一个温度计(Thermometer)类的实例:温度计类通过调用方法showMessage()显示有关信息时,需要根据当前自己温度(temperature)变量的值来显示有关信息,即根据自己的状态来决定showMessage()方法所体现的具体行为,这就要求showMessage()方法中有许多条件分支语句,例如:

public void showMessage(){
    if(temperature <= -20){
        System.out.println("现在是低温"+temperature);
     }
    if(temperature >= 30){
        System.out.println("现在是高温"+temperature);
    }
}

  我们注意到showMessage()方法的行为依赖于temperature的大小,这就使Thermometer类的实例在应对需求变化时缺乏弹性,不能很好地满足用户的需求。例如,有些用户可能需要温度计当其temperature的值大于60显示某些重要的信息;有些用户当其温度temperature的值在1825之间显示重要的信息。显然为达到上述要求,必须修改上面的代码才可以满足用户需求,者显然不是人们喜欢做的。

  现在我们需要重新考虑温度计(Thermometer)类的设计,发现温度计类中因用户需求变化而需要修改的代码都和对象的状态有关,即与温度的大小有关,因此,按照面向抽象、不面向实现的设计原则,应当将对象的状态从当前对象中分离出去,即将一个对象的状态封装在另外一个类中。现在,设计一个抽象类:TemperatureState类,该类规定了显示和温度有关的信息的方法showTemperature()。具体类关系图如下图一所示:

 

 

图一:封装对象的状态

    Thermometer类包含ThermometerState类声明的若干个变量,表面Thermometer类的实例:温度计类可以将任何温度计状态类的子类的实例作为自己的状态,而且温度计类的实例可以把和状态有关的请求委派给所维护状态的对象。

    状态模式的关键是将对象的状态封装成为独立的类,对象调用方法时,可以委托当前对象所具有的状态调用相应的方法,是当前对象看起来好像修改了它的类。

 

1.2模式的结构

状态模式包括以下三种角色:

(1)环境(Context):环境是一个类,该类含有抽象状态(State)声明的变量,可以引用任何具体状态类的实例。用户对该环境(Context)类的实例在某种状态下的行为感兴趣。

(2)抽象状态(State):抽象状态是一个接口或抽象类。抽象状态中定义了与环境(Context)的一个特定状态相关的若干个方法。

(3)具体状态(Concrete State):具体状态是实现(扩展)抽象状态(抽象类)的实例。

状态模式结构的类图如下图二所示:

 

 

图二:状态模式的类图

 

 

1.3状态模式的优点

1)使用一个类封装对象的一种状态,很容易增加新的状态。

2)在状态模式中,环境(Context)中不必出现大量的条件判断语句。环境(Context)实例所呈现的状态变得更加清晰、容易理解。

3)使用状态模式可以让用户程序很方便地切换环境实例的状态。

4)使用状态模式不会让环境的实例中出现内部状态不一致的情况。

5)当状态对象没有实例变量时,环境的各个实例可以共享一个状态对象。

 

1.4适合使用状态模式的情景

1)一个对象的行为依赖于它的状态,并且它必须在运行时根据状态改变它的行为。

2)需要编写大量的条件分支语句来决定一个操作的行为,而且这些条件恰好表示对象的一种状态。

 

 

1.5状态模式的使用

以下通过一个简单的问题来描述怎样使用状态模式,这个简单的问题就是:设计带文字提示信息的温度计。带文字提示信息的温度计可以根据用户的需求显示某些提示信息,比如用户希望温度在0度以下时,显示提示信息为“低温温度”,温度在10~26度之间时,显示提示信息为“正常温度”,当温度大于39度时,显示提示信息为“高温温度”。

首先看一下本实例构建框架具体类和1.2模式的结构中类图的对应关系,如下图所示:

 

(1)环境(Context

本问题中,环境角色是Thermometer类,代码如下:

package com.liuzhen.seventeen_state;

public class Thermometer {
    
    TemperatureState state;
    
    public void showMessage(){
        System.out.println("************");
        state.showTemperature();
        System.out.println("************");
    }
    
    public void setState(TemperatureState state){
        this.state = state;
    }
}

 

(2)抽象状态(State

对于本问题,抽象状态(State)是TemperatureState接口,代码如下:

package com.liuzhen.seventeen_state;

public interface TemperatureState {
    public void showTemperature();
}

 

(3)具体状态(Concrete State

对于本问题,共有三个具体状态角色,分别是LowStateMiddleStateHeightState类,代码如下:

LowState.java

package com.liuzhen.seventeen_state;

public class LowState implements TemperatureState{
    double n;
    LowState(double n){
        if(n <= 0)
            this.n = n;
    }
    public void showTemperature(){
        System.out.println("现在温度是"+n+",属于低温");
    }
}

MiddleState.java

package com.liuzhen.seventeen_state;

public class MiddleState implements TemperatureState{
    double n;
    MiddleState(double n){
        if(n > 0 && n < 26)
            this.n = n;
    }
    
    public void showTemperature(){
        System.out.println("现在温度是"+n+",属于正常温度");
    }
}

HeightState.java

package com.liuzhen.seventeen_state;

public class HeightState implements TemperatureState{
    double n;
    HeightState(double n){
        if(n > 39)
            this.n = n;
    }
    
    public void showTemperature(){
        System.out.println("现在温度是"+n+",属于高温");
    }
}

 

4)具体使用

  通过SeventeenApplication类来具体实现上述相关类和接口,来实现状态模式的运用,其代码如下:

package com.liuzhen.seventeen_state;

public class SeventeenApplication {
    public static void main(String[] args){
        TemperatureState state = new LowState(-12);
        Thermometer thermometer = new Thermometer();
        thermometer.setState(state);
        thermometer.showMessage();
        state = (TemperatureState) new MiddleState(20);
        thermometer.setState(state);
        thermometer.showMessage();
        state = (TemperatureState) new HeightState(50);
        thermometer.setState(state);
        thermometer.showMessage();
        
    }
}

 

运行结果:

************
现在温度是-12.0,属于低温
************
************
现在温度是20.0,属于正常温度
************
************
现在温度是50.0,属于高温
************

 

 

参考资料:

      1.Java设计模式/耿祥义,张跃平著.——北京:清华大学出版社,2009.5

状态模式——headfirst设计模式学习笔记

状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类——将状态封装成独立的类,将动作委托给当前状态对象,所以行为会随着内部状态的变化而变化  状态转换图:为每一个状态创建一个... 查看详情

设计模式学习笔记之状态模式

...同的状态会有不同的表现,通过更改状态从而改变表现的设计模式称为状态模式(state pattern)下边会通过多个例子进行讲述,会有一些代码重用的类,请注意包名!举例1:人有多种心情,不同的心情会有不同的表现,这里... 查看详情

23种设计模式(十七)——状态模式状态变化

状态模式文章目录状态模式意图什么时候使用状态真实世界类比状态模式的实现状态模式的优缺点亦称:State意图对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其... 查看详情

备忘录模式——headfirst设计模式学习笔记

备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。可以将该对象恢复到原先保存的状态Java中可以使用序列化机制保存状态发起人:记录当前时刻的内部状态,负责定义哪些属于... 查看详情

设计模式学习笔记(二十二:备忘录模式)

1.1概述  在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态。这就是备忘录模式的定义。 对象的状态依赖于它的变量的取值情况,对... 查看详情

蝇量模式——headfirst设计模式学习笔记

蝇量模式:让某个类的一个实例能够用来提供多个“虚拟”实例,运用共享技术有效地支持大量细粒度的对象 特点:减少运行时对象实例的个数将许多“虚拟”对象的状态一同管理运用共享技术有效地支持大量细粒度的对象... 查看详情

软件设计模式学习(十七)职责链模式(代码片段)

系统中如果存在多个对象可以处理一个同一请求,可以通过职责链模式将这些处理请求的对象连成一条链,让请求沿着该链进行传递。如果链上的对象可以处理该请求则进行处理,否则将请求转发给下家处理模式动机很多情况下... 查看详情

设计模式(十七):备忘录模式

一、概述   现实生活中的备忘录是用来记录某些要去做的事情,或者是记录已经达成的共同意见的事情,以防忘记了。而在软件层面,备忘录模式有着相同的含义,备忘录对象主要用来记录一个对象的某种状态,或者某些数... 查看详情

软件设计模式学习(二十七)访问者模式(代码片段)

访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素具有不同的类型,且不同的访问者可以对其进行不同的访问操作模式动机对于系统中某些对象,它们存储在同一个... 查看详情

学习十七

四周第二次课(2月27日)5.1vim介绍5.2vim颜色显示和移动光标5.3vim一般模式下移动光标5.4vim一般模式下复制、剪切和粘贴VIM介绍安装完之后会提示vim已安装vim打开文本是会出现这种有颜色的一般模式就直接esc进入编辑模式可以按i... 查看详情

设计模式学习笔记之状态模式(代码片段)

什么是状态模式呢?允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。。。是不是听起来显示在内部进行零件调换的感觉,其实是有点类似这种想法的,只不过调换的零件就是封装好的... 查看详情

java设计模式学习笔记

设计模式分为3大类型共23种:创建型:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型:策... 查看详情

zabbix学习笔记(四十七)

Zabbix学习笔记(四十七)-zabbix监控php-fpm状态​1、修改配置文件​/etc/php-fpm.d/www.conf​;pm.status_path=/status修改为pm.status_path=/php_status​/etc/nginx/nginx.conf增加:​location/php_status​fastcgi_passunix:/run/php-fpm/www.s 查看详情

设计模式学习笔记(十三:原型模式)

1.1概述  用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。这就是原型模式的定义。 在某些情况下,可能不希望反复使用类的构造方法创建许多对象,而是希望使用该类创建一个对象后,以该对... 查看详情

设计模式学习笔记(目录篇)

设计模式学习笔记(目录篇)为了方便查看,特此将设计模式学习笔记系列单独做一个目录。 1  设计模式学习笔记(一:命令模式)2  设计模式学习笔记(二:观察者模式)3  设计模式学习笔记(三:... 查看详情

中介者模式——headfirst设计模式学习笔记

中介者模式:集中管理相关对象之间的复杂沟通和控制  ------>>>>    特点:关系复杂的对象之间解耦了(对象之间必须相互认识->对象只认识中介者)中介者包含了整个系统的控制逻辑,控制逻辑... 查看详情

vuex学习笔记

一、vuex的目的  把组件的共享状态抽取出来,以一个全局单例模式管理。在这种模式下,组件树构成了一个巨大的视图,不管在树的哪个位置,任何组件都能获取状态或触发行为。二、vuex集中式管理数据  安装cnpmivuex  &... 查看详情

设计模式之观察者模式学习笔记(代码片段)

1、定义 定义对象间的一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,又叫发布-订阅(publish-subscribe)模式。 2... 查看详情