设计模式(20)——状态 State

24 篇文章 0 订阅
24 篇文章 3 订阅
目录:

设计模式学习笔记首页
设计模式(1)——抽象工厂 AbstractFactory
设计模式(2)——生成器 Builder
设计模式(3)——工厂方法 Factory Method
设计模式(4)——原型 Prototype
设计模式(5)——单例 Singleton
设计模式(6)——适配器 Adapter
设计模式(7)——桥接 Bridge
设计模式(8)——组合 Composite
设计模式(9)——装饰 Decorator
设计模式(10)——外观 Facade
设计模式(11)——享元 Flyweight
设计模式(12)——代理 Proxy
设计模式(13)——职责链 Chain Of Responsibility
设计模式(14)——命令 Command
设计模式(15)——解释器 Interpreter
设计模式(16)——迭代器 Iterator
设计模式(17)——中介者 Mediator
设计模式(18)——备忘录 Memento
设计模式(19)——观察者 Observer
设计模式(20)——状态 State
设计模式(21)——策略 Strategy
设计模式(22)——模板方法 Template Method
设计模式(23)——访问者 Visitor

二十、State(状态模式,别名 Objects for States 状态对象,对象行为型模式)

1. 意图:

  允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

2. 适用:

  1. 一个对象的行迹取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  2. 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State 模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

3. 类图:

image

4. State 与 Strategy

  State 模式和 Strategy 模式有很大程度上的相似:它们都有一个 Context 类,都是通过委托(组合)一个具有多个派生类的多态基类实现 Context 的算法逻辑。两者最大的差别就是 State 模式中派生类持有指向 Context 对象的引用,并通过这个引用调用Context中的方法,但在 Strategy 模式中就没有这种情况。因此可以说一个 State 实例同样是 Strategy 模式的一个实例,反之却不成立。实际上 State 模式和 Strategy 模式的区别还在于它们所关注的点不尽相同:State 模式主要是要适应对象对于状态改变的的不同处理策略的实现,而 Strategy 则主要是具体算法和实现接口的解耦(coupling),Strategy 模式中并没有状态的概念(虽然很多时候有可以被看作是状态的概念),并且更加不关心状态的改变了。
  State 模式很好地实现了对象的状态逻辑和动作实现的分离,状态逻辑分布在 State 的派生类中实现,而动作实现则可以放在 Context 类中实现(这也是为什么 State 派生类需要拥有一个指向 Context 的指针)。这使得两者的变化相互独立,改变 State 的状态逻辑可以很容易复用 Context 的动作,也可以在不影响 State 派生类的前提下创建 Context 的子类来更改或替换动作实现。
  State 模式问题主要是逻辑分散化,状态逻辑分布到了很多的 State 的子类中,很难看到整个的状态逻辑图,这也带来了代码的维护问题。

5. 思考:

  不能说状态模式一定是好的,只能说当行为 action 的数量是比较固定的情况下,使用状态模式才是好的。实现一个状态机有两种方式,第一种是将行为 action 封装起来,在行为函数中处理每一种状态。第二种方式是将状态 state 封装,在状态 state 中处理每一种行为 action。状态模式就是第二种方式。它将状态 state 封装成一个对象,在这个对象中处理每一种行为 action。这种方式添加状态很方便,只需要修改与新增状态有关的几个状态对象就可以了。但是这种方式添加行为很麻烦需要对所以状态对象做修改,来处理这种行为。所以说状态模式适用于行为 action 变动比较小,而状态变动比较频繁的情况。

6. C++实现:

  1. 编写一个环境类 Context, has-a 有一个 具体的 State 对象如 ConcreteStateA 对象 _state
  2. 编写 Context 的操作行为函数 OperationChangeState(),函数体内调用 _state 对象的与特定状态相关的具体行为
  3. 编写一个状态接口 State 以封装与 Context 的一个特定状态相关的行为,如接口 OperationInterface()OperationChangeState()
  4. 编写 State 中一个改变 Context 状态的方法 ChangeState(Context* con, State* st),State 在调用自己的操作行为 OperationChangeState() 时通过调用 ChangeState 方法来改变 Context 的状态,这样,下次 Context 再调用自己的操作函数(Context 的 OperationChangeState)时,就会调用改变后的新状态的操作函数(另一个 State 实现类的对象 的 OperationChangeState),这种执行操作行为后改变 Context 状态的机制就形成了状态机模式。
  5. Context 为了封装,其状态 _state 是私有的,所以为了让 State 实现类能够访问(改变)Context 状态,在 Context 中将 State 声明为其友元类 friend class State;
State.h
//State.h
#pragma once

class Context;

class State {
public:
    State();
    virtual ~State();
    virtual void OperationInterface(Context*) = 0;
    virtual void OperationChangeState(Context*) = 0;
    bool ChangeState(Context* con, State* st);
private:
};

class ConcreteStateA : public State {
public:
    ConcreteStateA();
    virtual ~ConcreteStateA();
    virtual void OperationInterface(Context*);
    virtual void OperationChangeState(Context*);
protected:
private:
};

class ConcreteStateB : public State {
public:
    ConcreteStateB();
    virtual ~ConcreteStateB();
    virtual void OperationInterface(Context*);
    virtual void OperationChangeState(Context*);
protected:
private:
};
State.cpp
//State.cpp
#include "State.h"
#include "Context.h"

#include <iostream>

using namespace::std;

State::State() {}
State::~State(){}
void State::OperationInterface(Context* con) {
    cout << "State::..." << endl;
}
bool State::ChangeState(Context* con, State* st) {
    con->ChangeState(st);
    return true;
}
void State::OperationChangeState(Context* con) {}

ConcreteStateA::ConcreteStateA() {}
ConcreteStateA::~ConcreteStateA() {}

void ConcreteStateA::OperationInterface(Context* con) {
    cout << "ConcreteStateA::OperationInterface......" << endl;
}
void ConcreteStateA::OperationChangeState(Context* con) {
    OperationInterface(con);
    this->ChangeState(con, new ConcreteStateB());
}
ConcreteStateB::ConcreteStateB() {}
ConcreteStateB::~ConcreteStateB() {}
void ConcreteStateB::OperationInterface(Context*  con) {
    cout << "ConcreteStateB::OperationInterface..." << endl;
}
void ConcreteStateB::OperationChangeState(Context* con) {
    OperationInterface(con);
    this->ChangeState(con, new ConcreteStateA());
}
Context.h
//Context.h
#pragma once

class State;

class Context {
public:
    Context();
    Context(State* state);
    ~Context();
    void OperationInterface();
    void OperationChangeState();
protected:
    friend class State; // 表明在 State 类中可以访问 Context 类的 private 字段
    bool ChangeState(State* state);
private:
    State* _state;
};
Context.cpp
//Context.cpp
#include "Context.h"
#include "State.h"

#include <iostream>
using namespace::std;

Context::Context(State* state) {
    this->_state = state;
}
Context::~Context() {
    delete _state;
}
void Context::OperationInterface() {
    _state->OperationInterface(this);
}
bool Context::ChangeState(State* state) {
    this->_state = state;
    return true;
}
void Context::OperationChangeState() {
    _state->OperationChangeState(this);
}
main.cpp
//main.cpp
#include "Context.h"
#include "State.h"

#include <iostream>
using namespace::std;

int main(int argc, char* argv[]) {
    State* st = new ConcreteStateA();
    Context* con = new Context(st);
    con->OperationChangeState();
    con->OperationChangeState();
    con->OperationChangeState();
    con->OperationChangeState();
    if(con != NULL)
        delete con;
    if(st != NULL)
        st = NULL;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值