简单易懂23种设计模式——状态模式【含C++代码实例】
23种设计模式C++实现——状态模式
在做面向对象的软件开发时我们往往想达到更高的代码可复用性和更合理的软件颗粒度。
根据《设计模式——可复用面向对象软件的基础》所说:“你必须找到相关的对象,以适当的颗粒度将他们回归类,再定义类的接口和继承层次,建立对象之间的基本关系。你的设计应该对手头的问题有针对性,同时对将来的问题和需求也要有足够的通用性。”1234
内行的设计者知道:不是解决任何问题都要从头做起。他们更愿意复用以前使用的解决方案。这些重复的模式方案解决特定的问题,使得面向对象的设计更灵活、优雅,最终复用性更好。它们帮助设计者将新的设计建立在以往的工作基础上,复用以往的成功设计方案。一个熟悉这些设计模式的设计者不需要再去发现它们,而能够立即将他们应用于设计问题中。
本系列文章主要参考文献为——设计模式,可复用面向对象软件的基础(Design Patterns Elements of Reusable Object-Oriented SoftWare Erich.),内部代码基本用C++语言编写。
汇总链接:23种设计模式C++实现——概要(索引汇总)
文章目录
摘要
本章主要说明状态模式,该设计模式主要意图是:在状态发生改变时对应的处理方法也发生改变。
允许一个对象在其内部改变时改变它的行为。
主要参与者
该设计模式的参与者有4个,分别是:
- AbstractState(DrawState)状态的接口
- ConcreteState(DrawRed DrawYellow DrawBlue)具体状态的实现
- Context(WhiteBoard)环境类,定义客户感兴趣的接口,维护一个ConcreteState的子类实例
- Client 用户
优缺点
优点
- 封装了转换规则,枚举可能的状态,在枚举状态之前需要确定状态的种类。
- 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
- 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
- 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点
- 状态模式的使用必然会增加系统类和对象的个数。
- 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
具体实现代码
这里实现一个绘图板的例子来说明状态模式,我们有个绘图板它有三种画笔颜色,分别是红色、黄色、蓝色,我们可以设置当前画笔的颜色之后再绘图板上绘制指定图形:
代码如下。
状态的接口(DrawState)
声明:
/****************************************************************
Doc : state.h
Author : BingLee
Date : 2020-08-17
Info : State Design Patten
https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef STATE_H
#define STATE_H
#include <QString>
class DrawState
{
public:
virtual ~DrawState();
virtual void paint(QString &str) = 0;
};
实现:
/****************************************************************
Doc : state.cpp
Author : BingLee
Date : 2020-08-17
Info : State Design Patten
https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#include "state.h"
#include <stdio.h>
DrawState::~DrawState()
{
printf("~DrawState()\n");
}
具体状态(ConcreteState)
DrawRed 红色画笔状态
声明:
class DrawRed : public DrawState
{
public:
DrawRed();
~DrawRed();
virtual void paint(QString &str);
};
实现:
DrawRed::DrawRed()
{
}
DrawRed::~DrawRed()
{
printf("~DrawRed()\n");
}
void DrawRed::paint(QString &str)
{
printf("Draw %s in Red.\n", str.toStdString().c_str());
}
DrawYellow 黄色画笔状态
声明
class DrawYellow : public DrawState
{
public:
DrawYellow();
~DrawYellow();
virtual void paint(QString &str);
};
实现
DrawYellow::DrawYellow()
{
}
DrawYellow::~DrawYellow()
{
printf("~DrawYellow()\n");
}
void DrawYellow::paint(QString &str)
{
printf("Draw %s in Yellow.\n", str.toStdString().c_str());
}
DrawBlue 蓝色画笔状态
声明:
class DrawBlue : public DrawState
{
public:
DrawBlue();
~DrawBlue();
virtual void paint(QString &str);
};
实现:
DrawBlue::DrawBlue()
{
}
DrawBlue::~DrawBlue()
{
printf("~DrawBlue()\n");
}
void DrawBlue::paint(QString &str)
{
printf("Draw %s in Blue.\n", str.toStdString().c_str());
}
环境类(WhiteBoard)
声明:
class WhiteBoard
{
public:
WhiteBoard(DrawState *state);
~WhiteBoard();
void setState(DrawState *state);
void draw(QString &str);
private:
DrawState *m_state;
};
#endif // STATE_H
实现:
WhiteBoard::WhiteBoard(DrawState *state)
{
m_state =state;
}
WhiteBoard::~WhiteBoard()
{
delete m_state;
}
void WhiteBoard::setState(DrawState *state)
{
delete m_state;
m_state = state;
}
void WhiteBoard::draw(QString &str)
{
m_state->paint(str);
}
用户(Client)
/****************************************************************
Doc : main.cpp
Author : BingLee
Date : 2020-08-17
Info : State Design Patten
https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#include <QCoreApplication>
#include "state.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
WhiteBoard *whiteBoard = new WhiteBoard(new DrawRed());
QString drawObj = "Circle";
whiteBoard->draw(drawObj);
whiteBoard->setState(new DrawYellow());
whiteBoard->draw(drawObj);
whiteBoard->setState(new DrawBlue());
whiteBoard->draw(drawObj);
delete whiteBoard;
return a.exec();
}
输出结果:
补充说明
通过上边这个简单的例子希望能说明什么是状态模式(state),其实上边这个例子在《Github design-patterns-for-humans》2有简单介绍但是并没有实现,博主感觉不错所以通过c++实现这个例子,在参考的文章中还有一个简单文本编辑器的例子,通过不同的状态转换输入文字的大小写,其实这两个例子曲异同工,都是状态模式的一种体现,如果有问题可以在博客下留言交流~
本篇博客中的代码均已通过编译,如有Bug,请提出宝贵意见~
注:文章内函数可以把除Client对象的声明放在一个头文件中,实现放在一个文件中,Client文件放在主函数中执行。
参考:
-
《设计模式——可复用面向对象软件的基础 》 ↩︎