从零开始学设计模式(十八):状态模式(State Pattern)

简介: 状态模式(State Pattern)指的是将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化,在其内部状态改变时改变它的行为。状态模式是一种对象行为型模式。它和策略模式有一点很像,就是将一些复杂的逻辑放在一个专门的上下文类中进行处理。

定义


状态模式(State Pattern)指的是将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化,在其内部状态改变时改变它的行为。状态模式是一种对象行为型模式。它和策略模式有一点很像,就是将一些复杂的逻辑放在一个专门的上下文类中进行处理。


往往在一个系统中的某个对象会存在多个状态,而且这些状态之间可以进行转换,并且在不同的状态下会具有不同的行为或者功能,比如很多喜欢看电视的朋友有时候用腾讯视频看电视,如果不充值会员的话,会有广告,而且很多vip的节目也不能观看了,冲了会员就没了广告,而且也能解锁vip节目,这时候用户就拥有两个状态,一个是vip状态,一个是非vip状态,而且在不同的状态下也有不同的行为,这时候的系统设计就可以使用状态模式。


组成部分


状态模式包含以下三个主要部分:


1、抽象状态类(State):它主要定义了一个公共接口或者抽象方法,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。


2、具体状态类(Concrete State):它主要就是继承或者实现抽象状态类/接口,并且实现抽象状态所对应的行为,在需要的情况下进行状态切换。


3、环境类(Context):也叫上下文,它内部维护一个当前状态,并负责具体状态的切换,最终给客户端调用。


例子


首先定义一个抽象的状态类,并且有抽象的行为方法:


public abstract class State {
    public abstract void Do();
}
复制代码


接着定义两个具体的状态子类去继承抽象的状态类,并且实现抽象方法:


public class ConcreteState1 extends State {
    @Override
    public void Do() {
        System.out.println("吃跑了,来外面散散步");
    }
}
public class ConcreteState2 extends State {
    @Override
    public void Do() {
        System.out.println("肚子很饿,需要吃饭");
    }
}
复制代码


接着定义一个上下文类,即环境类,用来处理状态和行为:


public class Context {
    // 维护一个抽象状态对象的引用
    private State state;
    public State getState() {
        return state;
    }
    public void setState(State state) {
        this.state = state;
    }
    public boolean isHungry() {
        return isHungry;
    }
    public void setHungry(boolean hungry) {
        isHungry = hungry;
    }
    private boolean isHungry;
    private void checkStates(){
        if(isHungry){
            //如果饿了的状态需要做饭
            setState(new ConcreteState2());
        }else{
            //吃饱了,出去走走
            setState(new ConcreteState1());
        }
    }
    public void process(){
        checkStates();
        state.Do();
    }
}
复制代码


测试方法:


public class StatePatternTest {
    public static void main(String[] args) {
        Context context = new Context();
        //设置状态为饿了
        context.setHungry(true);
        context.process();
        //设置状态为不饿
        context.setHungry(false);
        context.process();
    }
}
复制代码


运行结果:


429ce6b8109c4f15ba3234a09d3f093e~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


上面状态的处理,切换改变,除了可以在上下文类中实现,还可以在具体的状态子类中实现,比如:


首先需要在上下文类中初始化一个状态实例对象,并且将上下文对象作为子类的状态的构造参数传递给具体的子类中,上下文类代码:


// 设置初始状态  
this.state = new ConcreteStateA(this);
复制代码


然后在具体的子类状态类中根据构造进来的上下文类实例对象,通过调用它的属性值进行业务逻辑判断 进行状态的检查和切换。比如在ConcreteState1类的代码修改如下:


public class ConcreteState3 extends State {
    private Context context;
    public ConcreteState3(Context context){
        context= context;
    }
    @Override
    public void Do() {
        System.out.println("吃跑了,来外面散散步");
        checkState();
    }
    /**
     * 检查状态 是否需要进行状态的转换<br/>
     * 状态的切换由具体状态子类中实现     */
    private void checkState(){
        if (context.getisHungry()) {
            context.setState(new ConcreteState1(context));
        }
    }  
}
复制代码


状态模式的优点


1、状态模式的代码结构清晰,它将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,体现了“单一职责原则”。


2、将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。


3、每个具体的状态类负责具体的职责,有利于程序的扩展。可以增加新的子类来增加新的状态和行为。


1、同状态模式的第三个优点,拓展的同时会增加代码量,每增加一个新的子类,都会增加代码中类的个数;


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


应用场景


1、对象的行为依赖于它的状态并且可以根据它的状态改变而改变它的相关行为,比如前面说的会员系统;


2、一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。比如常见的if else结构的代码,或者switch语句等等。


总结


状态模式总结起来是如果一个对象的行为依赖于状态或者属性,那么可以将状态和行为拆分封装在一个环境类中处理,然后具体的子类负责具体行为。


最后本文以及之前的所有的设计模式中的例子代码,都将同步至github,需要的欢迎下载star。

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