状态模式和策略模式
策略模式,简而言之就是解决某个问题的方法。最近在玩原神,而原神由于其氪金机制和各种运行操作使得网上风评不高,而从玩家大体上分为3类:氪金大佬、中小氪和白嫖。而从策略模式分析,为了去抽到角色和武器需要解决方法,而方法分为三种:直接648、氪金+小肝、直接肝报废。而在其中有很多相同的地方,比如消耗相同、肝的方式相同等等。而策略模式就是将一个算法架构放于基类,减少代码重复,之后将某些待拓展点抽象化或者多态操作,使得拓展方便,并且不需要修改基类的算法架构。
状态模式,用来实现状态变化的操作。比如你小时候是4条腿走路、青年是2条、老年是3条,像这样的实现可能比较简单,一个判断分支就行了,可是由于状态变化的时候,可能随之改变的东西很多,比如年纪、身体状况、经济、家庭情况等等,这样的状态变化的情况就可能仅仅使用判断语句了,因此出现状态模式,简而言之,状态模式就是用处理当一个东西的状态改变的时候,数据或者操作变化太过于复杂的时候所用的一种易拓展模式。
基础UML
| 策略模式 | 状态模式 |
Strategy/State | 抽象基础类,大部分情况存储一个算法的共同数据和函数。比如基本价格等等 | 状态抽象类,大部分情况下存储抽象的共同函数,比如状态下的处理函数 |
ConcreateXXXX | 实际算法节点实现类。当算法中的一些方法节点需要拓展的时候,将节点归类为另外一个方法而派生为一个子类 | 具体状态实现类。 将东西的状态分离,实现每个状态下需要存储的数据或者进行的操作 |
Context/Handle | 外部的接口类。 | |
使用场景 | 当一系列类存在很多的相同点,只有一些行为不同的时候 当不同的情况需要动态的使用不同的节点处理方式的时候 | 状态变化的时候,行为或者数据随之变化的时候 当可能存在分支很庞大的时候,同来替代 |
优点 | 可以自由切换算法的某些行为 避免了可能的多条件判断 易拓展 | 可以用枚举方式省掉许多指针或者对象的传递 每个状态一个类去实现自己需要的行为,易拓展 在使用的时候,可以将不同的变量使用同一个状态类, 减少了类。比如长大状态,涉及到许多因素。 |
缺点 | 当方法很多的时候,会导致类比较多 由于客户端使用的方法,会导致所以的类暴露,因此常用中间控件来进行限制 | 结构和行为比较复杂,因此需要使用仔细 部分支持“开发封闭”,因为可能导致有些地方需要修改 |
相同点 | 易拓展 常用中间件在类组和用户之间减少操作和权限设置 | |
差异点 | 常用于共同点较多的情况,子类只是实现某些特定需求 目的是为在不同的要求下是用不同的方法 | 常用于状态变化的时候,涉及到的数据或者方法变化过大的情况 目的是为了减少状态变化后导致随之变化太过复杂的情况 |
实操
UML
关于两个模式的思维方式其实大致相同:
1.分析
策略模式:主要分析那些是可共享的,那些是不可共享
状态模式:主要分析分成那些状态,而对应状态的行为、数据是什么
2.继承和派生
只需要先单一的实现基类和派生类就行了
3.中间类的设定
在写完类组之后,会发现客户端使用比较麻烦,因此给定中间状态,设定权限和简化操作等等
4.看是否需要支持自动跳转
看是否需要用责任链的方式,实现状态自动选择的情况
而策略模式和状态模式在实现、uml大致是相同的,不同的在于关注点不同:
策略主要关注方法和行为的多种
状态主要关注变化时操作和行为变化太复杂
策略模式代码
// StrategyModel.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
using namespace std;
#define interface struct
interface IKillBoss
{
public:
virtual void ToKillBoss() = 0;
};
class CKillStrategyA:public IKillBoss
{
public:
void ToKillBoss()
{
cout << "屠龙宝刀,只卖999,任何boss不用愁!" << endl;
}
};
class CKillStrategyB :public IKillBoss
{
public:
void ToKillBoss()
{
cout << "白色大剑 + 普通的肝 , 小氪 +肝,慢慢打穿。" << endl;
}
};
class CKillStrategyC :public IKillBoss
{
public:
void ToKillBoss()
{
cout << "七彩大腰子 , 只要还没肝硬化,那个boss都不怕。" << endl;
}
};
class CKillStrategyChoose
{
private:
IKillBoss* m_kill;
public:
CKillStrategyChoose(int num)
{
if (0 == num)
{
m_kill = new CKillStrategyA();
}
else if (1 == num)
{
m_kill = new CKillStrategyB();
}
else if (2 == num)
{
m_kill = new CKillStrategyC();
}
}
void KillStrategy()
{
if (m_kill)
m_kill->ToKillBoss();
}
};
int main()
{
CKillStrategyChoose kill1(0);
kill1.KillStrategy();
CKillStrategyChoose kill2(1);
kill2.KillStrategy();
CKillStrategyChoose kill3(2);
kill3.KillStrategy();
}
状态模式代码
// StateModel.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
using namespace std;
class CWalk;
class IPeopleState
{
public:
virtual void howToWalk(CWalk *walk) = 0;
};
class COldState :public IPeopleState
{
void howToWalk(CWalk *walk)
{
cout << "老人用3条腿走路。" << endl;
}
};
class CYoungState:public IPeopleState
{
void howToWalk(CWalk *walk)
{
cout << "青年人用2条腿走路。" << endl;
}
};
class CChildState :public IPeopleState
{
public:
void howToWalk(CWalk *walk)
{
cout << "小孩用4条腿走路。" << endl;
}
};
class CWalk
{
private:
IPeopleState* m_state;
int m_age;
public:
CWalk()
{
m_state = NULL;
m_age = 0;
}
int getAge() { return m_age; }
void setAge(int age) { m_age = 0; }
void setState(IPeopleState* state) { m_state = state; }
void toWalk() { m_state->howToWalk(this); }
};
int main()
{
IPeopleState* state1 = new CChildState();
IPeopleState* state2 = new CYoungState();
IPeopleState* state3 = new COldState();
CWalk *walk = new CWalk();
walk->setState(state1);
walk->toWalk();
walk->setState(state2);
walk->toWalk();
walk->setState(state3);
walk->toWalk();
}