好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

深入理解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)的一个特定状态相关的行为。

?

1

2

3

4

public abstract class state

{

     public abstract void writeprogram(work w);

}

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

//上午工作状态

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();

         }

     }

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

//中午工作状态

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();

         }

     }

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

//下午工作状态

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();

         }

     }

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

//晚上工作状态

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();

             }

         }

     }

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

//睡眠工作状态

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子类(工作状态类)的实例,这个实例定义当前的状态

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

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 );

     }

}

客户端代码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

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判断,这对于一些复杂的和繁琐的判断逻辑有很好的帮助。但是使用状态模式,势必会造成更多的接口和类,对于非常简单的状态判断,可以不使用。

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

原文链接:https://HdhCmsTestcnblogs测试数据/xuwendong/p/9814423.html

查看更多关于深入理解Java设计模式之状态模式的详细内容...

  阅读:14次