状态模式

一、动机与定义

1、现实世界中的情况

在现实世界中,有很多事物的行为是和它当前所处的状态紧密相关的,比如水的三态下分别有各自独特的行为,人在处于不同的状态是会有不同的行为:

水在不同状态下有不同的行为


人在不同状态下有不同的行为

对于上图,如果采取最原始的编程方式,建立一个Person类,在类中建立各种方法:

最原始的编程方式

class  Person
{
    private String state;

    public boolean sing(){
        if (state.equals("happy")){
            do/sing;
            return true;
        } else
            return false;
    }

    public boolean eat(){
        if (state.equals("happy")){
            do/eat;
            return true;
        } else
            return false;
    }

    public boolean hit(){
        if (state.equals("sad")){
            do/hit;
            return true;
        } else
            return false;
    }

    public boolean shopping(){
        if (state.equals("sad")){
            do/shopping;
            return true;
        } else
            return false;
    }
}

这是一种最原始的编码方式,对于这种情况,当我们考虑以下情况时,就能很容易发现它的缺点
1、在某一状态下有很多行为
2、想要查看某一状态下都有哪些相应的行为
3、添加一个新的状态及在此状态下的行为

有上述情况时,该类的编码会变得非常混乱,由此我们可以总结这种编程方式的缺点:
1、大量的if语句重复编写
2、状态和相应行为的关系不够直观
3、添加新的状态修改了太多内部代码

对于上述缺点,我们可能想到采用继承的方式进行改进,改进后的类图如下:

采用继承方式改进的类图

class Person 
{
    private String state;
}

class HappyPerson{
    private String state = "happy";
    public void sing(){
        do/sing;
    }
    public void eat(){
        do/eat;
    }
}

class SadPerson{
    private String state = "sad";
    public void hit(){
        do/hit;
    }
    public void shopping(){
        do/shopping;
    }
}

改进后的类有点很明显:
1、省去大量if语句
2、状态和相应行为比较直观
3、添加一个新的状态新建一个继承类

但是仔细分析的话,这样的编码还是存在问题:
1、不符合实际情况(实际中应该只有一个对象)
2、继承暴露了太多父类的信息,和父类耦合度高


或许我们对该问题继续改进:将对象的状态和该状态下的行为封装起来,通过关联的形式和原类分离。
以上编程方式的改进过程这就是状态模式的动机:
1、在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态对象。
2、当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
3、将拥有状态的对象和状态对应的行为分离,这就是状态模式的动机

以下列出状态的相关定义:
1、状态模式又名状态对象
2、对象行为型模式
3、用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题
4、将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化
5、对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理
6、状态模式定义:允许一个对象在其内部状改变时改变它的行为,对象看起来似乎修改了它的类

二、结构与分析

下面是状态模式的结构类图
状态模式结构类图

上图是最重要的状态模式的类图,对其分析如下:
1、状态模式描述了对象状态的变化以及对象如何在每一种状态下表现出不同的行为
2、状态模式的关键是引入了一个抽象类来专门表示对象的状态,即抽象状态类,而对象的每一种具体状态类都继承了该类,并在不同具体状态类中实现了不同状态的行为,包括各种状态之间的转换
3、环境类实际上就是拥有状态的对象,环境类有时候可以充当状态管理器的角色,可以在环境类中对状态进行切换操作/4、抽象状态类可以是抽象类,也可以是接口,不同状态类就是继承这个父类的不同子类,具体状态类的产生是由于环境类存在多个状态,同时还满足两个条件:这些状态经常需要切换,在不同的状态下对象的行为不同

三、实例与解析

实例1:论坛用户等级

论坛中的用户有不同的等级,处于不同等级时方法不同:
论坛用户等级分类


此时可以设计类的关系如下:

论坛用户等级类图

四、模式优缺点

1、模式优点

1、封装了状态的转换规则,可以对状态转换代码进行集中管理,提高了代码的可维护性
2、将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为
3、允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块
4、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数

2、模式缺点

1、会增加系统中类和对象的个数,导致系统运行开销增大
2、结构与实现都较为复杂,如果使用不当将导致程序结构和代码混乱,增加系统设计的难度
3、对开闭原则的支持不太好,增加新的状态类需要修改负责状态转换的源代码,否则无法转换到新增状态;而且修改某个状态类的行为也需要修改对应类的源代码

五、效果与应用

1、模式使用环境

以下情况下可以使用状态模式:
1、对象的行为依赖于它的状态(例如某些属性值),状态的改变将导致行为的变化
2、在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强

2、模式应用

1、在工作流或游戏等类型的软件中广泛使用,如在政府OA办公系统中,一个批文的状态有多种:尚未办理、正在办理、正在批示、正在审核、已经完成等各种状态,而且批文状态不同时对批文的操作也有所差异。使用状态模式可以描述工作流对象(如批文)的状态转换以及不同状态下所具有的行为
2、在目前主流的RPG(Role Play Game 角色扮演游戏)中,使用状态模式可以对游戏角色进行控制,游戏角色的升级伴随着其状态的变化和行为的变化

六、状态模式扩展

1、共享状态

在有些情况下多个环境对象需要共享同一个状态,如果希望在系统中实现多个环境对象实例共享一个或多个状态对象,那么需要将这些状态对象定义为环境的静态成员对象。

例子:两个开关控制同一个灯,两开关状态必须保持一致

2、简单状态模式与可切换状态模式

简单状态模式:指状态都相互独立,状态之间无须进行转换的状态模式,是最简单的一种状态模式。遵循开闭原则,在客户端可以针对抽象状态类进行编程,而将具体状态类写到配置文件中,同时增加新的状态类对原有系统也不造成任何影响

可切换状态的状态模式:大多数的状态模式都是可以切换状态的状态模式,在实现状态切换时,在具有状态类内部需要调用环境类Context的setState()方法进行状态的转换操作。状态类与环境类之间通常还存在关联关系或者依赖关系。增加新的状态类可能需要修改其他某些状态类甚至环境类的源代码,否则系统无法切换到新增状态

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值