zoukankan      html  css  js  c++  java
  • 设计模式之状态模式

    状态模式的介绍:(重点就在这句)状态模式中的行为是由状态来决定的,不同的状态下有不同的行为。

    状态模式和策略模式的结构几乎是一样的,但是他们的目的,本质却完全不一样。

    状态模式的行为是平行的,不可替换的

    策略模式的行为是独立的,可以相互替换的

    用一句话来表述,状态模式把对象的行为封装在不同的状态类中,每一个状态对象(状态类的实例)都有一个共同的抽象状态基类。

    状态模式的意图是让一个对象在其内部状态改变时,其行为也随之改变

    状态模式的定义:当一个对象的内部状态发生改变时允许其改变行为

    状态模式使用场景:(下面两个场景很重要)

    (1)一个对象的行为取决于它的状态,并且它必须在运行时根据状态来改变其行为

    (2)代码中把包含大量与对象状态有关的条件语句,例如,一个操作中含有庞大的多分支语句 if else 或者 switch case ,且这些分支依赖于该对象的状态

    状态模式是将每一个条件分支放入一个独立的类中,这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化,

    这样通过多态来去除过多的,重复的if else 等分支语句

     

    下面就以电视遥控器为例来演示一下状态模式的实现。我们首先将电视的状态简单分为开机状态和关机状态,在开机状态下,可以通过遥控器进行频道切换,调整音量等操作,但是,此时重复按开机键是无效的,而在关机状态下,频道切换,音量操作是无效的操作,只有按开机按钮时会生效,也就是说电视的内部状态决定了遥控器的行为。

    结合上面的状态模式的定义:开机和关机就是所说的状态。频道切换和调整音量操作就是行为。状态能影响行为,和使用的场景(1)是可以对得上了。

    状态改变,其行为也会改变,例如电视开机状态下,是可以把音量调大或者调小的,如果此时电视机状态变为关机了,音量就不可以调了。是不是状态改变了就可以影响到了行为了,这和上面的状态模式的介绍也可以对得上了。

    是的,状态模式就是这样一个模式,行为受状态的影响。和策略模式有点像,但是要记得,是有本质区别的。

    以上面的例子,看一下第一版的实现。

    复制代码
     1 /**
     2  *
     3  * 电视遥控器,含有开机,关机,下一频道,上一频道,调高音量,调低音量
     4  */
     5 public class TvController {
     6     //开机状态
     7     private final static int POWER_ON   = 1;
     8     //关机状态
     9     private final static int POWER_OFF  = 2;
    10     private int mState = POWER_OFF;
    11 
    12     //开机
    13     public void powerOn(){
    14         mState = POWER_ON;
    15         if(mState == POWER_OFF){
    16             System.out.println("开机啦");
    17         }
    18     }
    19 
    20 
    21     //关机
    22     public void powerOff(){
    23         mState = POWER_OFF;
    24         if(mState == POWER_ON){
    25             System.out.println("关机啦");
    26         }
    27     }
    28 
    29     //下一频道
    30     public void nextChannel(){
    31         if(mState == POWER_ON){
    32             System.out.println("下一频道");
    33         }else {
    34             System.out.println("两个红灯提示没有开机");
    35         }
    36     }
    37 
    38     //上一频道
    39     public void preChannel(){
    40         if(mState == POWER_ON){
    41             System.out.println("上一频道");
    42         }else {
    43             System.out.println("两个红灯提示没有开机");
    44         }
    45     }
    46 
    47     //调高音量
    48     public void turnUp(){
    49         if(mState == POWER_ON){
    50             System.out.println("调高音量");
    51         }else {
    52             System.out.println("两个红灯提示没有开机");
    53         }
    54     }
    55 
    56     //调低音量
    57     public void turnDown(){
    58         if(mState == POWER_ON){
    59             System.out.println("调低音量");
    60         }else {
    61             System.out.println("两个红灯提示没有开机");
    62         }
    63     }
    64 
    65 
    66 }
    复制代码

    可以看到,在TvController类中,通过mState字段存储了电视的状态,并且在各个操作中根据状态来判断是否应该执行。这就导致了在每个功能中都需要使用if else,代码重复,相对较为混乱,这是在只有两个状态和几个简单的功能函数的情况下,如果状态变成5个,10个呢?每个函数都要有if else 判断,而这些代码都充斥在一个类中,这些重复的代码无法被提取出来,这使得这个类变得越来越难以维护。

      状态模式就是为这类问题而出现的,我们将这些状态用状态对象来代替,将这些行为封装在状态类中,使得在不同的状态下有不同的实现,这样就将这些if else 从

    TvController类中去掉,整个结构也简单变得清楚起来,我们看看实现的代码:

    复制代码
    1 /**
    2  * 电视状态接口,定义了电视操作的函数
    3  */
    4 public interface TvState {
    5     void nextChannel();     //下一个频道
    6     void preChannel();      //上一个频道 
    7     void turnUp();          //调高音量
    8     void turnDown();        //调低音量
    9 }
    复制代码

     

    开机状态

    复制代码
     1 /**
     2  * 开机状态
     3  */
     4 public class PowerOnState implements TvState{
     5     @Override
     6     public void nextChannel() {
     7         System.out.println("下一个频道");
     8     }
     9 
    10     @Override
    11     public void preChannel() {
    12         System.out.println("上一个频道");
    13     }
    14 
    15     @Override
    16     public void turnUp() {
    17         System.out.println("调高音量");
    18     }
    19 
    20     @Override
    21     public void turnDown() {
    22         System.out.println("调低音量");
    23     }
    24 }
    复制代码

     

    关机状态

    复制代码
     1 /**
     2  * 关机状态
     3  */
     4 public class PowerOffState implements TvState{
     5     @Override
     6     public void nextChannel() {
     7 
     8     }
     9 
    10     @Override
    11     public void preChannel() {
    12 
    13     }
    14 
    15     @Override
    16     public void turnUp() {
    17 
    18     }
    19 
    20     @Override
    21     public void turnDown() {
    22 
    23     }
    24 }
    复制代码

     

    电源操作接口

    复制代码
    1 /**
    2  * 电源操作接口
    3  */
    4 public interface PowerControl {
    5     void powerOn();
    6     void powerOff();
    7 }
    复制代码

     

    电视遥控器

    复制代码
     1 /**
     2  * 遥控器
     3  */
     4 public class TvControl implements PowerControl{
     5     TvState mState;
     6 
     7     public void setState(TvState state){
     8         mState = state;
     9     }
    10 
    11     //改变为开机状态
    12     @Override
    13     public void powerOn() {
    14         //改变为开机状态,把状态设置为开机状态
    15         setState(new PowerOnState());
    16         System.out.println("开机啦");
    17     }
    18 
    19     //改变为关机状态
    20     @Override
    21     public void powerOff() {
    22         //改变为关机状态,把状态设置为开机状态
    23         setState(new PowerOffState());
    24         System.out.println("关机啦");
    25     }
    26 
    27     public void nextChannel(){
    28         mState.nextChannel();
    29     }
    30 
    31     public void preChannel(){
    32         mState.preChannel();
    33     }
    34 
    35     public void turnUp(){
    36         mState.turnUp();
    37     }
    38 
    39     public void turnDown(){
    40         mState.turnDown();
    41     }
    42 
    43 }
    复制代码

     

    下面是客户端测试类

    复制代码
     1 /**
     2  * 客户端测试类
     3  */
     4 public class StateTest {
     5 
     6     public static void main(String[] args){
     7         test();
     8     }
     9 
    10 
    11     public static void test(){
    12         //电视
    13         TvControl tvControl = new TvControl();
    14         //改变状态,看看是否影响行为
    15         tvControl.powerOn();
    16         //下一个频道
    17         tvControl.nextChannel();
    18         //调大音量
    19         tvControl.turnUp();
    20         //设置关机状态
    21         tvControl.powerOff();
    22         //调高音量,此时不会生效
    23         tvControl.turnUp();
    24     }
    25 }
    复制代码

    运行结果如下:

    开机啦
    下一个频道
    调高音量
    关机啦

    果然,状态改变时,行为也跟着改变了。

    本文转载自http://www.cnblogs.com/start1225/p/6736188.html

  • 相关阅读:
    JS函数浅析(一)
    H5_canvas与svg
    h5+js视频播放器控件
    【BZOJ3622】已经没有什么好害怕的了
    【9.29 模拟】T3 小清新最优化(easy)
    9.27模拟
    9.26 模拟
    4062 -- 【清华集训2012】串珠子
    【SNOI2017】炸弹
    P3216 [HNOI2011]数学作业
  • 原文地址:https://www.cnblogs.com/sparkleDai/p/7604897.html
Copyright © 2011-2022 走看看