深入理解Java设计模式之状态模式

目录
  • 一、什么是状态模式
  • 二、状态模式的结构
  • 三、状态模式的使用场景
  • 四、状态模式和策略模式对比
  • 五、状态模式的优缺点
  • 六、状态模式的实现
  • 七、总结

一、什么是状态模式

定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

主要解决:当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。

意图:允许一个对象在其内部状态改变时改变它的行为

二、状态模式的结构

在该类图中,我们看到三个角色:

(1)Context: 环境类,定义客户感兴趣的接口,维护一个State子类的实例,这个实例对应的是对象当前的状态。

(2)State:抽象状态类或者状态接口,定义一个或者一组行为接口,表示该状态下的行为动作。

(3)ConcreteState: 具体状态类,实现State抽象类中定义的接口方法,从而达到不同状态下的不同行为。

三、状态模式的使用场景

1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。

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

例子:我们在微博上看到一篇文章,觉得还不错,于是想评论或者转发,但如果用户没有登录,这个时候就会先自动跳转到登录注册界面,如果已经登录,当然就可以直接评论或者转发了。这里我们可以看到,我们用户的行为是由当前是否登录这个状态来决定的,这就是典型的状态模式情景。

当然还包括很多其他动作,例如转发、分享、打赏等等,都要重复判断状态才行,如果程序随着需求的改动或者功能逻辑的增加需要修改代码,那么你只要遗漏了一个判断,就会出问题。

而使用状态模式,可以很好地避免过多的if–else –分支,状态模式将每一个状态分支放入一个独立的类中,每一个状态对象都可以独立存在,程序根据不同的状态使用不同的状态对象来实现功能。

四、状态模式和策略模式对比

如果我们在编写代码的时候,遇到大量的条件判断的时候,可能会采用策略模式来优化结构,因为这时涉及到策略的选择,但有时候仔细查看下,就会发现,这些所谓的策略其实是对象的不同状态,更加明显的是,对象的某种状态也成为判断的条件。

策略模式的Context含有一个Strategy的引用,将自身的功能委托给Strategy来完成。

我们把Strategy接口改个名字为State,这就是状态模式了,同样Context也有一个State类型的引用,也将自己的部门功能委托给State来完成。

要使用状态模式,我们必须明确两个东西:状态和每个状态下执行的动作。

在状态模式中,因为所有的状态都要执行相应的动作,所以我们可以考虑将状态抽象出来。

状态的抽象一般有两种形式:接口和抽象类。如果所有的状态都有共同的数据域,可以使用抽象类,但如果只是单纯的执行动作,就可以使用接口。

他们之间真正的区别在策略模式对Strategy的具体实现类有绝对的控制权,即Context要感知Strategy具体类型。而状态模式,Context不感知State的具体实现,Context只需调用自己的方法,这个调用的方法会委托给State来完成,State会在相应的方法调用时,自动为Context设置状态,而这个过程对Context来说是透明的,不被感知的。

五、状态模式的优缺点

优点:

1、封装了转换规则。

2、枚举可能的状态,在枚举状态之前需要确定状态种类。

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

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

5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点:

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

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

3、状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

六、状态模式的实现

抽象状态类,定义一个接口以封装与Context类(Work)的一个特定状态相关的行为。

public abstract class State
{
    public abstract void WriteProgram(Work w);
}

工作状态类,每一个子类实现一个与Context类(Work)的一个状态相关的行为。

//上午工作状态
public class ForeNoonState : State
{
    public override void WriteProgram(Work w)
    {
        if (w.Hour < 12)
        {
            Console.WriteLine("当前时间:{0}点,上午工作,精神百倍", w.Hour);
        }
        else
        {
            //超过12点,则转入中午工作状态
            w.SetState(new NoonState());
            w.WriteProgram();
        }
    }
}
//中午工作状态
public class NoonState : State
{
    public override void WriteProgram(Work w)
    {
        if (w.Hour < 13)
        {
            Console.WriteLine("当前时间:{0}点,吃午饭,午休", w.Hour);
        }
        else
        {
            //超过13点,则转入下午工作状态
            w.SetState(new AfterNoonState());
            w.WriteProgram();
        }
    }
}
//下午工作状态
public class AfterNoonState : State
{
    public override void WriteProgram(Work w)
    {
        if (w.Hour < 17)
        {
            Console.WriteLine("当前时间:{0}点,下午工作,继续努力", w.Hour);
        }
        else
        {
            //超过17点,则转入晚上工作状态
            w.SetState(new EveningState());
            w.WriteProgram();
        }
    }
}
//晚上工作状态
public class EveningState : State
{
    public override void WriteProgram(Work w)
    {
        if (w.Finish)
        {
            //如果状态已完成,则转入下班状态
            w.SetState(new RestState());
            w.WriteProgram();
        }
        else
        {
            if (w.Hour < 21)
            {
                Console.WriteLine("当前时间:{0}点,加班", w.Hour);
            }
            else
            {
                //超过21点,则转入睡眠工作状态
                w.SetState(new SleepingState());
                w.WriteProgram();
            }
        }
    }
}
//睡眠工作状态
public class SleepingState : State
{
    public override void WriteProgram(Work w)
    {
        Console.WriteLine("当前时间:{0}点,睡觉", w.Hour);
    }
}
//下班休息状态
public class RestState : State
{
    public override void WriteProgram(Work w)
    {
        Console.WriteLine("当前时间:{0}点,下班", w.Hour);
    }
}

工作类,Context类,维护一个ConcreteState子类(工作状态类)的实例,这个实例定义当前的状态

public class Work
{
    private State current;
    public Work()
    {
        //工作初始化为上午工作状态
        current = new ForeNoonState();
    }
    //“钟点”属性,状态转换的依据
    private double hour;
    public double Hour
    {
        get { return hour; }
        set { hour = value; }
    }
    //“任务完成”属性,是否能下班的依据
    private bool finish = false;
    public bool Finish
    {
        get { return finish; }
        set { finish = value; }
    }
     public void SetState(State s)
    {
        current = s;
    }
     public void WriteProgram()
    {
        current.WriteProgram(this);
    }
}

客户端代码

class Program
{
    //客户端代码
    static void Main(string[] args)
    {
        Work w = new Work();
        w.Hour = 9;
        w.WriteProgram();
        w.Hour = 10;
        w.WriteProgram();
        w.Hour = 12;
        w.WriteProgram();
        w.Hour = 13;
        w.WriteProgram();
        w.Hour = 14;
        w.WriteProgram();
        w.Hour = 17;
         w.Finish = false;
        //w.Finish = true;
        w.WriteProgram();
        w.Hour = 19;
        w.WriteProgram();
        w.Hour = 22;
        w.WriteProgram();
         Console.Read();
    }
}

结果

当前时间:9点,上午工作,精神百倍
当前时间:10点,上午工作,精神百倍
当前时间:12点,吃午饭,午休
当前时间:13点,下午工作,继续努力
当前时间:14点,下午工作,继续努力
当前时间:17点,加班
当前时间:19点,加班
当前时间:22点,睡觉

七、总结

在对象的行动取决于本身的状态时,可以适用于状态模式,免去了过多的if–else判断,这对于一些复杂的和繁琐的判断逻辑有很好的帮助。但是使用状态模式,势必会造成更多的接口和类,对于非常简单的状态判断,可以不使用。

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 23种设计模式(22)java状态模式

    一.概述 当系统中某个对象存在多个状态,这些状态之间可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式.状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化.状态模式是一种对象行为型模式. 二.适用场景 用于解决系统中复杂对象的多种状态转换以及不同状态下行为的封装问题.简单说就是处理对象的多种状态及其相互转换. 三.UML类图 四.参与者 1).AbstractState(抽象状态类): 在抽象状态类中定义申明了不同状态下的行为抽象方法,而由子类

  • java 设计模式之State(状态模式)

    java 设计模式之State(状态模式) 在状态模式中,一个类的行为基于它的状态的改变而改变.状态模式归属于行为型模式. 在下面的实例中,我们创建了一个接口State,定义了一个操作方法,两个实现类StartState和StopState.另外,创建了一个上下文类Context,这个类关联到State类.UML类图如下所示: //状态类 public interface State { public void doAction(Context context); } //实现类StartSta

  • Java设计模式之状态模式(State模式)介绍

    State的定义:不同的状态,不同的行为:或者说,每个状态有着相应的行为. 何时使用状态模式 State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了. 不只是根据状态,也有根据属性.如果某个对象的属性不同,对象的行为就不一样,这点在数据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property属性含义的字段,用以标识记录中一些特殊

  • Java设计模式之java状态模式详解

    目录 状态模式的结构 状态模式的角色 示例代码 适用场景 投票案例 认识状态模式 状态和行为 行为的平行性 环境和状态处理对象 状态模式优点 状态模式的缺点 状态模式和策略模式对比 参考文章 总结 状态模式的结构 用一句话来表述,状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类.状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变.状态模式的示意性类图如下所示: 状态模式的角色 环境(Context)角色,也成上下文:定义客户端所感兴

  • 对比Java设计模式编程中的状态模式和策略模式

    为了能在Java应用程序中正确的使用状态模式和策略模式,开发人员需要清楚地知道这两种模式之间的区别.尽管状态模式和策略模式的结构非常相似,它们又同样遵循开闭原则,都代表着SOLID设计原则的'O',但它们的意图是完全不同的.Java中的策略模式是对一组相关的算法进行封装,给调用方提供了运行时的灵活性.调用方可以在运行时选择不同的算法,而不用修改使用策略的那个Context类.使用策略模式的经典例子包括实现加密算法,压缩算法,以及排序算法.另一方面,状态模式使用一个对象可以在不同的状态下表现出不同

  • 详解JAVA 设计模式之状态模式

    在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式. 在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象. 介绍 意图: 允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类. 主要解决: 对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为. 何时使用: 代码中包含大量与对象状态有关的条件语句. 如何解决: 将各种具体的状态类抽象出来. 关键代码: 通常

  • 深入理解Java设计模式之状态模式

    目录 一.什么是状态模式 二.状态模式的结构 三.状态模式的使用场景 四.状态模式和策略模式对比 五.状态模式的优缺点 六.状态模式的实现 七.总结 一.什么是状态模式 定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 主要解决:当控制一个对象状态的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化. 意图:允许一个对象在其内部状态改变时改变它的行为 二.状态模式的结构 在该类图中,我们看到三个角色: (1)Cont

  • Java设计模式之状态模式State Pattern详解

    目录 概述 UML类图 状态模式与策略模式 谁决定状态转换的流向 State是接口还是抽象类 应用案例分析 状态抽象类 可以抽奖的状态 奖品发放完毕状态 发放奖品的状态 不能抽奖状态 抽奖活动(Context) 测试状态模式 概述 状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类.这个模式将状态封装成独立的类,并将动作委托到 代表当前状态的对象,我们知道行为会随着内部状态而改变. 一个对象“看起来好像修改了它的类”是什么意思呢?从客户的视角来看:如果说你使用的对象能够完全

  • Java设计模式之状态模式

    实际开发中订单往往都包含着订单状态,用户每进行一次操作都要切换对应的状态,而每次切换判断当前的状态是必须的,就不可避免的引入一系列判断语句,为了让代码更加清晰直观,我们引入今天的主角——状态模式. 一.概念理解 假设订单状态有,下单.发货.确认收货,如果用户确认收货,在常规编程中就要判断当前用户的状态,然后再修改状态,如果这种情况下使用状态模式. 将各个状态都抽象成一个状态类,比如下单状态类.发货状态类.确认收货类,在状态类中处理相应的逻辑和控制下一个状态,在定义一个环境类,定义初始状态,并控制

  • 深入理解Java设计模式之访问者模式

    目录 一.什么是访问者模式 二.访问者模式的结构 三.访问者模式的使用场景 四.访问者模式的优缺点 五.访问者模式的实现 总结 一.什么是访问者模式 定义:表示一个作用于其对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 可以对定义这么理解:有这么一个操作,它是作用于一些元素之上的,而这些元素属于某一个对象结构.同时这个操作是在不改变各元素类的前提下,在这个前提下定义新操作是访问者模式精髓中的精髓. 主要解决:稳定的数据结构和易变的操作耦合问题.就是把数据

  • 深入理解Java设计模式之策略模式

    目录 一.什么是策略模式 二.策略模式的结构 三.策略模式的应用场景 四.策略模式的优缺点 六.策略模式的实现 七.策略模式和简单工厂模式的结合 八.策略枚举的实现 九.总结 一.什么是策略模式 策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户.需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数. 策略模式定义和封装了一系列的算法,它们是可以相互替换的,也就是说它们具有

  • 深入理解Java设计模式之桥接模式

    目录 二.桥接模式的结构 三.桥接模式的使用场景 四.桥接模式的优缺点 五.装饰,桥接和适配器模式的异同 适配器模式: 桥接模式: 装饰器模式: 六.桥接模式的实现 七.总结 一.什么是桥接模式 桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化.它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式. 二.桥接模式的结构 在桥接模式结构图中包含如下几个角色: Abstraction(抽象类):用于定义

  • 理解java设计模式之建造者模式

    建造者模式(Builder Pattern)主要用于"分步骤构建一个复杂的对象",在这其中"分步骤"是一个稳定的算法,而复杂对象的各个部分则经常变化.因此, 建造者模式主要用来解决"对象部分"的需求变化. 这样可以对对象构造的过程进行更加精细的控制. package com.shejimoshi.create.Builder; /** * 功能:意图是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 * 适用性: * 当创

  • 深入理解Java设计模式之备忘录模式

    目录 一.什么是备忘录模式 二.备忘录模式的结构 三.备忘录模式的使用场景 四.备忘录模式的优缺点 五.备忘录模式的实现 总结 一.什么是备忘录模式 定义:在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 该模式用于保存对象当前状态,并且在之后可以再次恢复到此状态.备忘录模式实现的方式需要保证被保存的对象状态不能被对象从外部访问, 目的是为了保护被保存的这些对象状态的完整性以及内部实现不向外暴露 二.备忘录模式的结构 涉及角色:

随机推荐