设计模式之状态模式


在这里插入图片描述

1.定义

状态模式,又称状态机模式,属于行为型设计模式的一种,定义:允许一个对象在内部状态发生改变时改变其行为,就好像是改变了自身的类一样。

简单举个栗子,在传统方式下,我们根据一个对象的状态改变其行为的做法通常是这样的:

if obj.state == 1 then .... else...
if obj.state == 2 then .... else ...

如果状态简单,这种if else语句看上去是没有问题的,但是如果状态变得复杂起来,多种状态之间互相作用,关联,这种代码就会变得非常复杂,比如使用大量的flag去维护状态和状态之间的转换,使得这部分代码变得难以维护,最重要的是这部分代码将在客户端进行维护,客户端不得不关心各个状态之间的转换和具体的行为。

既然状态的转换和具体的行为难以在客户端维护,那根据面向对象的思考方式,就可以将这部分进行单独的抽象分离,将状态抽象出来成为单独的类,而状态的行为,转换自然也应该由状态对象来维护
(状态知道自己是谁,知道自己能够支持哪些行为,知道状态转换细节),客户端这个时候就不需要维护当前状态或者状态之间的转换。

这个过程本质上是利用了多态的原理,与策略模式有点类似,策略模式是将不同的处理方式抽象成一个相互独立的策略,策略之间是平等的,而状态模式强调的是平行性。

状态模式将对象的行为封装在不同的状态对象中,将对象的状态从对象中分离出来,客户端无需关心对象的当前状态和状态的抓换

状态模式角色:

  • 抽象状态角色(State):状态类的抽象,应该定义维护状态所对应的行为方法
  • 具体状态角色(Concrete State):具体状态类,实现相应的行为方法
  • 上下文对象(Context):持有状态的对象,应包含状态对象的实例

UML:
在这里插入图片描述
图片来源:知乎

2.示例

以文件状态的切换为例,简单状态模式进行实现,假设一个文件有三种状态,分别是打开、关闭和移除,文件只能打开一次,当文件打开之后可以关闭,但不能删除,已被删除的文件所有的操作都是非法操作。
打开文件、关闭文件、删除文件这些相当于是可以影响状态的行为,也就是说不同的状态下有不同的行为。

首先对状态进行单独的抽象,并定义状态对应的行为

/**
 * @description: 文件状态
 * @version: 1.0
 */
public interface FileState {

    void openFile(DocFile docFile);

    void closeFile(DocFile docFile);

    void removeFile(DocFile docFile);
}

对三种状态分别进行实现,定义各自状态的行为特征以及状态转换

/**
 * @description: 打开文件状态
 * @version: 1.0
 */
public class OpenState implements FileState{
    @Override
    public void openFile(DocFile docFile) {
        System.out.println("当前文件已打开,请勿重复打开");
    }

    @Override
    public void closeFile(DocFile docFile) {
    	//由状态来完成状态转换
        docFile.setFileState(new CloseState());
        System.out.println("当前文件已打开,现在关闭文件");
    }

    @Override
    public void removeFile(DocFile docFile) {
        System.out.println("非法操作,当前文件已打开,无法删除");
    }
}
/**
 * @description: 关闭文件状态
 * @version: 1.0
 */
public class CloseState implements FileState{
    @Override
    public void openFile(DocFile docFile) {
        docFile.setFileState(new OpenState());
        System.out.println("当前文件未打开,现在打开文件");
    }

    @Override
    public void closeFile(DocFile docFile) {
        System.out.println("非法操作,当前文件未打开");
    }

    @Override
    public void removeFile(DocFile docFile) {
        docFile.setFileState(new RemoveState());
        System.out.println("当前文件未打开,现在删除文件");
    }
}

/**
 * @description: 删除文件状态
 * @version: 1.0
 */
public class RemoveState implements FileState{
    @Override
    public void openFile(DocFile docFile) {
        System.out.println("非法操作,无法打开文件,文件不存在");
    }

    @Override
    public void closeFile(DocFile docFile) {
        System.out.println("非法操作,无法关闭文件,文件不存在");
    }

    @Override
    public void removeFile(DocFile docFile) {
        System.out.println("非法操作,无法删除文件,文件不存在");
    }
}

最后定义一个上下文对象,这里可以是“文件对象”,文件对象应持状态实例,表示当前的状态

/**
 * @description: context
 * @version: 1.0
 */
public class DocFile {

	//持有状态对象
    private FileState fileState;

    public FileState getFileState() {
        return fileState;
    }

    public void setFileState(FileState fileState) {
        this.fileState = fileState;
    }

    public void openFile(){
        fileState.openFile(this);
    }

    public void closeFile(){
        fileState.closeFile(this);
    }

    public void removeFile(){
        fileState.removeFile(this);
    }
}

测试:

/**
 * @description: test
 * @version: 1.0
 */
public class Test {
    public static void main(String[] args) {
        DocFile docFile = new DocFile();
        docFile.setFileState(new CloseState());

        docFile.openFile();
        docFile.openFile();
        docFile.removeFile();
        docFile.closeFile();
        docFile.removeFile();
        docFile.openFile();

    }
}

input:

当前文件未打开,现在打开文件
当前文件已打开,请勿重复打开
非法操作,当前文件已打开,无法删除
当前文件已打开,现在关闭文件
当前文件未打开,现在删除文件
非法操作,无法打开文件,文件不存在

状态模式中客户端只需要和上下文对象交互,不需要关心状态的细节信息,上下文对象持有状态对象,对外提供客户端期待的行为,同时又将具体的状态处理细节委托给了状态对象,这符合面向对象的设计原则,需要注意的是,在上下文对象委托状态对象行为的时候,大多数情况下需要将自身的this指针传递给状态,以便状态对象在合适的时机进行回调,从而反过来影响上下文对象的状态。

3.总结

状态模式使用单独的类来封装一个状态的处理,将具体的控制逻辑代码分散到不同的状态对象中,简化了控制逻辑,增强了扩展性,只需要增加新的状态实现类,并设置状态变化到这个新状态即可,当一个对象具有不同的状态,而在不同的状态下回产生不同的行为变化,或者一个操作中有大量的分支操作,这些分支依赖一个对象的状态,可以考虑使用状态设计模式。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值