《设计模式的艺术》笔记 - 状态模式

介绍

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

实现

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <unordered_map>
#include <atomic>
#include <vector>
#include <memory>

class State {   // 抽象状态类
public:
    virtual void handle() = 0;
};

class Context { // 环境类
public:
    Context();
    void setState(const std::shared_ptr<State> &state);
    void request(int num);
    void changeState();

private:
    std::shared_ptr<State> m_state;
    int m_value;
};

class ConcreteStateA : public State {    // 具体状态类A
public:
    void handle() override;
};

class ConcreteStateB : public State {    // 具体状态类B
public:
    void handle() override;
};


#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"
#include <thread>
#include <unistd.h>
#include <sstream>

Context::Context() {
    m_value = 0;
    m_state.reset(new ConcreteStateA());
}

void Context::setState(const std::shared_ptr<State> &state) {
    m_state = state;
}

void Context::request(int num) {
    int tmp = m_value;
    m_value += num;
    if ((tmp >= 0 && m_value < 0) || (tmp < 0 && m_value >= 0)) {
        changeState();
    }
    m_state->handle();
}

void Context::changeState() {
    std::cout << "切换状态" << std::endl;
    if (m_value >= 0) {
        m_state.reset(new ConcreteStateA());
    } else {
        m_state.reset(new ConcreteStateB());
    }
}

void ConcreteStateA::handle() {
    std::cout << "ConcreteStateA::handle()" << std::endl;
}

void ConcreteStateB::handle() {
    std::cout << "ConcreteStateB::handle()" << std::endl;
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    Context *context = new Context;
    context->request(0);
    std::cout << "-------------------" << std::endl;
    context->request(-10);
    std::cout << "-------------------" << std::endl;
    context->request(20);

    return 0;
}

总结

优点

  1. 封装了状态的转换规则。在状态模式中可以将状态的转换代码封装在环境类或者具体状态类中,对状态转换代码进行集中管理,而不是分散在一个个业务方法中。

  2. 将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为。

  3. 允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块。状态模式可以避免使用庞大的条件语句来将业务方法和状态转换代码交织在一起。

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

缺点

  1. 状态模式的使用必然会增加系统中类和对象的个数,导致系统运行开销增大。

  2. 状态模式的程序结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,增加系统设计的难度。

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

适用场景

  1. 对象的行为依赖于它的状态(例如某些属性值),状态的改变将导致行为的变化。

  2. 在代码中包含大量与对象状态有关的条件语句。这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强。

练习

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <unordered_map>
#include <atomic>
#include <vector>
#include <memory>

class Level {   // 抽象状态类
public:
    virtual void play() = 0;
    virtual void doubleScore();
    virtual void changeCards();
    virtual void peekCards();
};

class CardsGame {
public:
    CardsGame();
    ~CardsGame();

    void play(int score);   // 模拟玩游戏得分
    void doubleScore();
    void changeCards();
    void peekCards();

private:
    Level *m_level;     // 当前等级
    Level *m_primary;   // 入门级
    Level *m_secondary; // 熟练级
    Level *m_professional;  // 高手级
    Level *m_final;     // 骨灰级
    int m_score;    // 得分
};

class PrimaryLevel : public Level {
public:
    void play() override;

    void doubleScore() override;

    void changeCards() override;

    void peekCards() override;
};

class SecondaryLevel : public Level {
public:
    void play() override;

    void changeCards() override;

    void peekCards() override;
};

class ProfessionalLevel : public Level {
public:
    void play() override;

    void peekCards() override;
};

class FinalLevel : public Level {
public:
    void play() override;
};


#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"
#include <thread>
#include <unistd.h>
#include <sstream>

void Level::doubleScore() {
    std::cout << "胜利积分加倍" << std::endl;
}

void Level::changeCards() {
    std::cout << "换牌" << std::endl;
}

void Level::peekCards() {
    std::cout << "偷看他人的牌" << std::endl;
}

CardsGame::CardsGame() {
    m_primary = new PrimaryLevel();
    m_secondary = new SecondaryLevel();
    m_professional = new ProfessionalLevel();
    m_final = new FinalLevel();
    m_level = m_primary;
    m_score = 0;
}

CardsGame::~CardsGame() {
    if (m_primary) {
        delete m_primary;
    }
    if (m_secondary) {
        delete m_secondary;
    }
    if (m_professional) {
        delete m_professional;
    }
    if (m_final) {
        delete m_final;
    }
}

void CardsGame::play(int score) {
    m_level->play();
    m_score += score;
    if (m_score < 100) {
        if (m_level != m_primary) {
            std::cout << "切换到入门级" << std::endl;
            m_level = m_primary;
        }
    } else if (m_score < 500) {
        if (m_level != m_secondary) {
            std::cout << "切换到熟练级" << std::endl;
            m_level = m_secondary;
        }
    } else if (m_score < 1000) {
        if (m_level != m_professional) {
            std::cout << "切换到高手级" << std::endl;
            m_level = m_professional;
        }
    } else {
        if (m_level != m_final) {
            std::cout << "切换到骨灰级" << std::endl;
            m_level = m_final;
        }
    }
}

void CardsGame::changeCards() {
    m_level->changeCards();
}

void CardsGame::doubleScore() {
    m_level->doubleScore();
}

void CardsGame::peekCards() {
    m_level->peekCards();
}

void PrimaryLevel::play() {
    std::cout << "入门级游戏开始" << std::endl;
}

void PrimaryLevel::doubleScore() {
    std::cout << "入门级不支持游戏胜利积分加倍功能" << std::endl;
}

void PrimaryLevel::changeCards() {
    std::cout << "入门级不支持换牌功能" << std::endl;
}

void PrimaryLevel::peekCards() {
    std::cout << "入门级不支持偷看他人的牌功能" << std::endl;
}

void SecondaryLevel::play() {
    std::cout << "熟练级游戏开始" << std::endl;
}

void SecondaryLevel::changeCards() {
    std::cout << "熟练级不支持换牌功能" << std::endl;
}

void SecondaryLevel::peekCards() {
    std::cout << "熟练级不支持偷看他人的牌功能" << std::endl;
}

void ProfessionalLevel::play() {
    std::cout << "高手级游戏开始" << std::endl;
}

void ProfessionalLevel::peekCards() {
    std::cout << "高手级不支持偷看他人的牌功能" << std::endl;
}

void FinalLevel::play() {
    std::cout << "骨灰级游戏开始" << std::endl;
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    CardsGame *cardsGame = new CardsGame();
    cardsGame->doubleScore();
    cardsGame->changeCards();
    cardsGame->peekCards();
    cardsGame->play(200);
    std::cout << "------------------------" << std::endl;
    cardsGame->doubleScore();
    cardsGame->changeCards();
    cardsGame->peekCards();
    cardsGame->play(500);
    std::cout << "------------------------" << std::endl;
    cardsGame->doubleScore();
    cardsGame->changeCards();
    cardsGame->peekCards();
    cardsGame->play(500);
    std::cout << "------------------------" << std::endl;
    cardsGame->doubleScore();
    cardsGame->changeCards();
    cardsGame->peekCards();
    cardsGame->play(0);

    delete cardsGame;

    return 0;
}
相关推荐
丝斯20113 小时前
AI学习笔记整理(42)——NLP之大规模预训练模型Transformer
人工智能·笔记·学习
凉、介5 小时前
深入 QEMU Guest Agent:虚拟机内外通信的隐形纽带
c语言·笔记·学习·嵌入式·虚拟化
GISer_Jing5 小时前
AI Agent 目标设定与异常处理
人工智能·设计模式·aigc
njsgcs5 小时前
SIMA2 论文阅读 Google 任务设定器、智能体、奖励模型
人工智能·笔记
蔺太微6 小时前
组合模式(Composite Pattern)
设计模式·组合模式
云半S一6 小时前
pytest的学习过程
经验分享·笔记·学习·pytest
AI视觉网奇6 小时前
ue5.7 配置 audio2face
笔记·ue5
鱼跃鹰飞7 小时前
DDD中的防腐层
java·设计模式·架构
会员果汁9 小时前
15.设计模式-组合模式
设计模式·组合模式
崎岖Qiu9 小时前
【OS笔记35】:文件系统的使用、实现与管理
笔记·操作系统·存储管理·文件系统·os