状态模式:一种行为设计模式,当一个对象的内部状态改变时允许改变其行为。
状态机的一些区别:
-
状态机强调的更多是一种状态之间的一种状态转换,每个状态之间的转化关系,更多强调的是这一点,更像是一个思想或者说是算法
-
状态模式是面向对象的设计模式,强调通过封装状态和行为来达到松耦合,通常在设计阶段确定。而状态机则更偏重于算法和逻辑,描述了状态之间的转换条件。
-
状态模式通常会有更多的开销(更多的类和对象),因为每个状态都是一个单独的类。而状态机可以用更简单的数据结构(如表)来实现。
-
状态模式更适用于大型项目和复杂系统,因为它可以提高代码的可读性和可维护性。而在处理简单状态转换的情况下,状态机可能是更合适的选择
真实世界的类比:
电梯:每一种状态,都对应着不同的行为(比如上行这个状态,电梯就会向上运动)
ATM:有存钱和取钱两种状态(如果是取钱的话,就会从出钱口退钱;如果是存钱的话,就需要我们往内存钱)
Super Mario:(每一种Mario都可以相互转化,每一种状态都有不同的行为动作)
游戏应用场景:
- 游戏场景切换:首先他们都可以继承共有的场景这个抽象类,然后不同的场景有不同的行为属性,就类似于登陆场景是玩家登陆,战斗场景就是玩家战斗
- 玩家游戏行为:不同的技能可能有不同的技能分支,导致会有不同的效果
优点:
- 单一职责原则: 将与特定状态相关的代码放在单独的类中
- 开闭原则: 无需修改已有状态类和上下文就能引入新状态
- 通过消除臃肿的状态条件语句,简化上下文代码
马里奥三者转化的一些例子
//
// mario.cpp
// design-pattern
//
// Created by Le Li on 2021/8/9.
//
#include <stdio.h>
#include <iostream>
template<typename T>
class Singleton
{
public:
static T& GetInstance()
{
static T instance;
return instance;
}
Singleton(T&&) = delete;
Singleton(const T&) = delete;
void operator= (const T&) = delete;
protected:
Singleton() = default;
virtual ~Singleton() = default;
};
class Mario;
class MarioState {
public:
virtual void GotMushroom(Mario* mario) = 0;
virtual void GotFireFlower(Mario* mario) = 0;
};
class Mario {
private:
MarioState* state;
int coin;
public:
Mario();
void SetState(MarioState* state);
public:
void SetCoin(int numberOfCoins);
void ReportCoin();
public:
void GotMushroom();
void GotFireFlower();
};
class SmallMario : public MarioState, public Singleton<SmallMario> {
public:
void GotMushroom(Mario* mario);
void GotFireFlower(Mario* mario);
};
class SuperMario : public MarioState, public Singleton<SuperMario> {
public:
void GotMushroom(Mario* mario);
void GotFireFlower(Mario* mario);
};
class FireMario : public MarioState, public Singleton<FireMario> {
public:
void GotMushroom(Mario* mario);
void GotFireFlower(Mario* mario);
};
Mario::Mario() {
coin = 0;
this->state = &SmallMario::GetInstance();
}
void Mario::SetState(MarioState* state) {
this->state = state;
}
void Mario::SetCoin(int numberOfCoins) {
std::cout << "Got Coins: " << numberOfCoins << std::endl;
coin += numberOfCoins;
}
void Mario::ReportCoin() {
std::cout << "Total Coin: " << coin << std::endl;
}
void Mario::GotMushroom() {
this->state->GotMushroom(this);
};
void Mario::GotFireFlower() {
this->state->GotFireFlower(this);
};
void SmallMario::GotMushroom(Mario *mario) {
mario->SetCoin(100);
mario->SetState(&SuperMario::GetInstance());
}
void SmallMario::GotFireFlower(Mario *mario) {
mario->SetCoin(200);
mario->SetState(&FireMario::GetInstance());
}
void SuperMario::GotMushroom(Mario *mario) {
mario->SetCoin(50);
}
void SuperMario::GotFireFlower(Mario *mario) {
mario->SetCoin(300);
mario->SetState(&FireMario::GetInstance());
}
void FireMario::GotMushroom(Mario *mario) {
mario->SetCoin(100);
}
void FireMario::GotFireFlower(Mario *mario) {
mario->SetCoin(100);
}
int main() {
std::unique_ptr<Mario> mario(new Mario());
mario->GotMushroom();
mario->ReportCoin();
return 0;
}
在C++中,内置类型(也称为基本类型或原始类型)是语言核心部分定义的类型,不需要任何用户定义的类或组件。
非内置类型: 指的就是自己创建的那些普通的类,比如class a{}之类的
内置类型: 就比如int,double之类的
new a和new a()的一些区别需要判断你是内置类型还是非内置类型
如果是非内置类型的话,new A和new A()都会调用默认构造函数创建对象。
如果是内置类型的话,new A和new A()的行为不同。
int main() {
int* a1 = new int;
int* a2 = new int();
std::cout << *a1 << "\n"; // 该值是未初始化的,可能是任何值。
std::cout << *a2 << "\n"; // 该值被初始化为0。
delete a1;
delete a2;
return 0;
}
这里,new int创建了一个新的int,但不进行初始化,所以a1的值是未定义的。而new int()创建了一个新的int并将其初始化为0,所以a2的值是0。
因此,如果你正在创建内置类型的对象,并且希望它们被初始化为0,应该使用 new A() 的形式。对于自定义类型,new A和new A()等价。