状态模式

21次阅读

共计 1263 个字符,预计需要花费 4 分钟才能阅读完成。

简介

状态模式,指当一个对象的内部状态发生改变时,允许改变它的行为。

UML 类图

示例

这里我们使用播放器的播放和停止两个状态来模拟状态模式,如下:
状态类,state.h

#ifndef STATE_H
#define STATE_H
#include <iostream>

using namespace std;
#define SAFE_DELETE(p) if(p){delete (p); (p) = NULL;}
class CPlayerContext;
class CState
{
public:
    virtual void Switch(CPlayerContext* pContext) = 0;
};

class CPlayState:public CState
{
public:
    void Switch(CPlayerContext* pContext);
};

class CStopState:public CState
{
public:
    void Switch(CPlayerContext* pContext);
};

class CPlayerContext
{
public:
    void Request();
    CState* GetState()
    {return m_pState;}
    void SetState(CState* pState)
    {m_pState = pState;}
private:
    CState* m_pState;
};
#endif

状态类实现,state.cpp

#include "state.h"

void CPlayState::Switch(CPlayerContext* pContext)
{CState* pState = pContext->GetState();
    SAFE_DELETE(pState);
    cout<<"Play->Stop"<<endl;
    pContext->SetState(new CStopState);
}

void CStopState::Switch(CPlayerContext* pContext)
{CState* pState = pContext->GetState();
    SAFE_DELETE(pState);
    cout<<"Stop->Play"<<endl;
    pContext->SetState(new CPlayState);
}

void CPlayerContext::Request()
{m_pState->Switch(this);
}

客户端调用,main.cpp

#include "state.h"

int main(int argc, char* argv[])
{
    CPlayerContext* pContext = new CPlayerContext;
    CState* pState = new CStopState;
    pContext->SetState(pState);
    pContext->Request();
    pContext->Request();
    SAFE_DELETE(pState);
    SAFE_DELETE(pContext);
    return 0;
}

输出如下:

Stop->Play
Play->Stop

正文完
 0

状态模式

21次阅读

共计 1713 个字符,预计需要花费 5 分钟才能阅读完成。

状态模式

在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。
在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。

意图主要解决

允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类
对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。

优点

  • 封装了转换规则。
  • 枚举可能的状态,在枚举状态之前需要确定状态种类。
  • 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
  • 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
  • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点

  • 状态模式的使用必然会增加系统类和对象的个数。
  • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
  • 状态模式对 ” 开闭原则 ” 的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

状态模式实现

  1. class Menu

我们使用 es6 实现一个类的创建, 便于我们多个地方重复使用,其实状态模式是要根据你的状态
来实现或者操作你想要的东西

    class Menu{}
  1. 状态对象

创建一个状态对象或者数组,内部保存状态变量,然后内部封装好每种动作对应的状态,然后状态对象返回一个接口对象,它可以对内部的状态修改或者调用。

    this.menuStates = {hide:function () {console.log("hide")
        },
        show: function () {console.log("show")
        },
        left: function () {console.log("left")
        },
        right: function () {console.log("right")
        }
    }

上面就是我们的状态对象,一共有四个状态函数,做出不同的操作和实现

  1. 具体的使用函数

触发我们要执行的状态,state 是我要传递 callback 函数参数,我们会根据传递的函数进行调用执行它,当然在执行过程当中
我们还可以设定使用其它的抽象类,以达到我们想要的单一原则,不要在乎是不是这样写比以前那样代码还多了,
确实会多,但是复用的时候你再看看是否还会再那么的繁琐以及更多的代码编写

    toggle (state) {state()
    }

代码组合实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
class Menu {constructor(state){
        this.num = 1
        this.menuStates = {hide:function () {console.log("hide")
            },
            show: function () {console.log("show")
            },
            left: function () {console.log("left")
            },
            right: function () {console.log("right")
            }
        }
    }
    toggle (state) {state()
    }
}

    var menu = new Menu()
    console.log(menu)
    menu.toggle(menu.menuStates.show)
    menu.toggle(menu.menuStates.hide)
</body>
<script>

</script>
</html>

上面图片就是我们得到的结果我们会发现 menu 构造函数是拥有四个状态函数,我们通过使用 toggle 函数来调用我们的函数,其实说白了状态模式相对于其它模式还是比较简单的,但是对于它的使用场景你要了解,你是否可以真正的运用它,以及把它放在适用的场景上。
状态模式是指允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。以逗号分割,把这句话分为两部分来看。第一部分的意思是将状态封装成独立的类,并将请求委托给当前的状态对象,当对象的内部状态改变时,会带来不同的行为变化。

正文完
 0

状态模式

21次阅读

共计 2127 个字符,预计需要花费 6 分钟才能阅读完成。

模拟电梯
定义电梯接口
public interface ILift{
// 开门
public void open();
// 关门
public void close();
// 能运行
public void run();
// 停
public void stop();
}
实现
public class Lifi implements ILift{
// 关闭
public void close(){
// 关门
}
// 开门
public void open(){
// 开门
}
// 运行
public void run(){
// 运行
}
// 停止
public void stop(){
// 停止
}
}
书写场景类
public class Client{
public static void main(String[] args){
ILift lift = new Lift();
// 开门
lift.open();
// 关门
lift.close();
// 运行
lift.run();
// 停止
lift.stop();
}
}
更改
目前不清楚电梯的状态,所以增加电梯的状态
public interface ILift{
// 四个状态
// 开门
public final static int OPENING_STATE = 1;
// 关门
public final static int CLOSEING_STATE = 2;
// 运行
public final static int RUNNING_STATE = 3;
// 停止
public final static int STOPPING_STATE = 4;
// 设置状态
public void setState(int state);
// 下方相同
}
// 实现类
public class Lift implements ILift{
private int state;
public void setState(int state){
this.state = state;
}
// 当电梯门关闭
public void close(){
// 关闭
switch(this.state){
case OPENING_STATE; // 关门
this.closeWithoutLogic();
// 修改状态
}
}
// 下方同理
}
修改
对电梯的状态进行封装,当调用的时候,直接自动改变电梯的状态。即,迪米特法则即,外界不需要知道电梯的状态,为一个封装好的。
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 OpenningState extends LiftState{
// 关门
@Override
public void close(){
// 状态更改
super.context.setLiftState(Context.closeingState);
// 委托执行
super.context.getLiftState().close();
}
// 打开电梯门
@Override
public void open(){
// 开门
}
// 运行
@Override
public void run(){
// 门开,禁止运行
}
// 关门
@Override
public void stop(){
// 开门的状态即停止
}
}
// 环境类,用于封装当前电梯的状态
public class Context{
// 定义电梯状态
public final static OpenningState openningState = new OpenningState();
// 剩下三个状态相同
// 当前状态
private LiftState liftState;
// 获得状态
public LiftState getLiState(){
return liftState;
}
// 设置状态
public LiftState setLiftState(LiftState liftState){
this.liftState = liftState;
// 通知到当前的状态
this.liftState.setContext(this);
}
}
剩下的几个相同
// 书写场景类
public class Client{
public static void main(String[] args){
// 此时定义一个电梯的状态
Context context = new Context();
// 此时电梯进入关闭状态
// 将关闭状态,保存进入 context 中
// 进行通知, 将当前状态的父类设置为 context
context.setLiFtState(new ClosingState());
// 代执行 ClosingState
context.open();
// 发生关闭状态的时候,
context.close();
context.run();
context.stop();
}
}
总结
状态模式的核心在于封装,将对象的状态进行封装。在于通知,当状态发生改变的时候,进行通知。

正文完
 0