设计模式19 - 状态模式【State Pattern】

简介: 设计模式19 - 状态模式【State Pattern】

状态模式

定义:

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


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


举例(电梯例子,代码是最终结果):

分析:电梯类里面过多的判断状态,导致类十分庞大,所以分到不同状态的一系列类中去。

/**
* 定义一个电梯的接口
*/
public abstract class LiftState{ 
    //定义一个环境角色,也就是封装状态的变换引起的功能变化
    protected Context context; 
    public void setContext(Context _context){ 
         this.context = _context; 
    } 
    //首先电梯门开启动作
    public abstract void open(); 
    //电梯门有开启,那当然也就有关闭了
    public abstract void close(); 
    //电梯要能上能下,跑起来
    public abstract void run(); 
    //电梯还要能停下来,停不下来那就扯淡了
    public abstract void stop(); 
} 
public class Context { 
    //定义出所有的电梯状态
    public final static OpenningState openningState = new OpenningState(); 
    public final static ClosingState closeingState = new ClosingState(); 
    public final static RunningState runningState = new RunningState(); 
    public final static StoppingState stoppingState = new StoppingState(); 
    //定一个当前电梯状态
    private LiftState liftState; 
    public LiftState getLiftState() { 
         return liftState; 
    } 
    public void setLiftState(LiftState liftState) { 
         this.liftState = liftState; 
         //把当前的环境通知到各个实现类中
         this.liftState.setContext(this); 
     } 
    public void open(){ 
         this.liftState.open(); 
     } 
    public void close(){ 
         this.liftState.close(); 
     } 
    public void run(){ 
         this.liftState.run(); 
     } 
    public void stop(){ 
         this.liftState.stop(); 
     } 
} 
/**
* 在电梯门开启的状态下能做什么事情
*/
public class OpenningState extends LiftState { 
    //开启当然可以关闭了,我就想测试一下电梯门开关功能
    @Override
    public void close() { 
     //状态修改
     super.context.setLiftState(Context.closeingState); 
     //动作委托为CloseState来执行
     super.context.getLiftState().close(); 
 } 
    //打开电梯门
    @Override
    public void open() { 
         System.out.println("电梯门开启..."); 
    } 
    //门开着电梯就想跑,这电梯,吓死你!
    @Override
    public void run() { 
         //do nothing;
     } 
    //开门还不停止?
    public void stop() { 
         //do nothing;
    } 
} 
/**
* 电梯门关闭以后,电梯可以做哪些事情
*/
public class ClosingState extends LiftState { 
    //电梯门关闭,这是关闭状态要实现的动作
    @Override
    public void close() { 
         System.out.println("电梯门关闭..."); 
     } 
    //电梯门关了再打开,逗你玩呢,那这个允许呀
    @Override
    public void open() { 
         super.context.setLiftState(Context.openningState); //置为门敞状态
         super.context.getLiftState().open(); 
     } 
    //电梯门关了就跑,这是再正常不过了
    @Override
    public void run() { 
         super.context.setLiftState(Context.runningState); //设置为运行状态;
         super.context.getLiftState().run(); 
     } 
    //电梯门关着,我就不按楼层
    @Override
    public void stop() { 
         super.context.setLiftState(Context.stoppingState); //设置为停止状态;
         super.context.getLiftState().stop(); 
     } 
} 
/**
* 电梯在运行状态下能做哪些动作
*/
public class RunningState extends LiftState { 
    //电梯门关闭?这是肯定了
    @Override
    public void close() { 
         //do nothing
    } 
    //运行的时候开电梯门?你疯了!电梯不会给你开的
    @Override
    public void open() { 
         //do nothing
     } 
    //这是在运行状态下要实现的方法
    public void run() { 
         System.out.println("电梯上下跑..."); 
     } 
    //这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了
    @Override
    public void stop() { 
         super.context.setLiftState(Context.stoppingState); //环境设置为停止状态;
         super.context.getLiftState().stop(); 
    } 
} 
/**
* 在停止状态下能做什么事情
*/
public class StoppingState extends LiftState { 
    //停止状态关门?电梯门本来就是关着的!
    @Override
    public void close() { 
      //do nothing;
    } 
    //停止状态,开门,那是要的
    @Override
    public void open() { 
      super.context.setLiftState(Context.openningState); 
      super.context.getLiftState().open(); 
   } 
    //停止状态再跑起来,正常的很
    @Override
    public void run() { 
      super.context.setLiftState(Context.runningState); 
      super.context.getLiftState().run(); 
      } 
    //停止状态是怎么发生的呢?当然是停止方法执行了
    @Override
    public void stop() { 
          System.out.println("电梯停止了..."); 
    } 
}  
public class Client { 
    public static void main(String[] args) { 
         Context context = new Context(); 
         context.setLiftState(new ClosingState()); 
         context.open(); 
         context.close(); 
         context.run(); 
         context.stop(); 
     } 
} 

总结:

意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。

主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。

何时使用:代码中包含大量与对象状态有关的条件语句。

如何解决:将各种具体的状态类抽象出来。

关键代码:通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if…else 等条件选择语句。

优点:

1、封装了转换规则。

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

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

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

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

缺点:

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

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

使用场景: 1、行为随状态改变而改变的场景。 2、条件、分支语句的代替者。

注意事项:在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。

用设计模式的时候并不是完全的嵌套,主要是使用到了相关的场景时,可以考虑到使用设计模式。然后在去分析如何嵌套使用。



目录
相关文章
|
3月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
3月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
3月前
|
设计模式 Java 测试技术
Java设计模式-状态模式(18)
Java设计模式-状态模式(18)
|
4月前
|
设计模式 网络协议 Java
【十五】设计模式~~~行为型模式~~~状态模式(Java)
文章详细介绍了状态模式(State Pattern),这是一种对象行为型模式,用于处理对象在其内部状态改变时的行为变化。文中通过案例分析,如银行账户状态管理和屏幕放大镜工具,展示了状态模式的应用场景和设计方法。文章阐述了状态模式的动机、定义、结构、优点、缺点以及适用情况,并提供了Java代码实现和测试结果。状态模式通过将对象的状态和行为封装在独立的状态类中,提高了系统的可扩展性和可维护性。
【十五】设计模式~~~行为型模式~~~状态模式(Java)
|
5月前
|
设计模式 JavaScript Go
js设计模式【详解】—— 状态模式
js设计模式【详解】—— 状态模式
91 7
|
6月前
|
设计模式
设计模式-05建造者模式(Builder Pattern)
设计模式-05建造者模式(Builder Pattern)
|
7月前
|
设计模式 安全 Java
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
该文介绍了一种C++的编程技巧——奇异递归模板模式(CRTP),旨在让派生组件能继承基本组件的特定功能。通过示例展示了如何创建一个`Fighter`接口和`MmaFighter`类,其中`MmaFighter`及其子类如`MmaBantamweightFighter`和`MmaHeavyweightFighter`强制类型安全,确保相同重量级的拳手之间才能进行比赛。这种设计避免了不同重量级拳手间的错误匹配,编译时会报错。CRTP适用于处理类型冲突、参数化类方法和限制方法只对相同类型实例生效的情况。
|
6月前
|
设计模式
状态模式-大话设计模式
状态模式-大话设计模式
|
6月前
|
设计模式 存储
行为设计模式之状态模式
行为设计模式之状态模式
|
7月前
|
设计模式 Go
[设计模式 Go实现] 行为型~状态模式
[设计模式 Go实现] 行为型~状态模式