备忘录模式:在不破换封装性的前提下,获取一个对象的内部状态,并且在对象外保存这个状态,以后可以使对象恢复到被保存的状态。
大家都玩过游戏,在游戏的世界里你可以一往无前,不停的打怪升级。还有一个重要的特点就是,可以死而复生,也就是说,你在游戏世界中虽然被击败了但是复活后可以继续战斗。游戏里面还会设置各种神奇的药水,保证你在受到攻击下还可以快速的恢复体力继续战斗。
那么咱们根据以上场景搭建一个游戏玩家,这个玩家可以玩游戏,可以受到攻击,生命值下降:
class Player {
public:
Player();
~Player();
void play();
//受到攻击
void attacked();
void getStateInfo();
private:
int _speed = 100;//初始化速度值
int _life = 100;//初始化生命值
int _power = 100;//初始化力量值
}
Player::Player() {
}
Player::~Player() {
}
void Player::play() {
printf("开始游戏\n");
}
void Player::attacked() {
printf("受到攻击! - ");
_speed -= 20;
_life -= 20;
_power -= 20;
}
void Player::getStateInfo() {
printf("当前的生命值:%d 速度值:%d 力量值:%d\n", _life, _speed, _power);
}
基本的游戏玩家已经搭建完成了,看看客户端的调用:
int main() {
Player* player = new Player;
player->play();
player->getStateInfo();
//受到两次攻击
for (int i = 0; i < 2; i++){
player->attacked();
player->getStateInfo();
}
return 0;
}
运行一下:
游戏玩家产生之后开始进行游戏,并且受到了两次攻击,生命也在减少了。在这时恰好捡到了一瓶神奇的药水,使用了这瓶药水之后,生命值恢复到一些,恢复到第一次攻击后的状态。
既然是可以恢复到之前的状态那么应该就应该知道之前的状态是多少,需要保存起来。
那么应该是由谁来保存之前的状态?有游戏玩家自己保存?如果由游戏玩家自己来保存的话,也就是说游戏玩家自己知道自己之前的状态,这就有点矛盾了,游戏玩家自己知道自己的状态,自己就可以自动恢复了还需要喝什么神奇的药水嘛。理论上不应该游戏玩家来保存了,应该有第三方对象来保存。那么保存什么内容呢?保存的是游戏玩家的基本状态,也就是生命值等属性信息。
那么我们就定义一个状态类,用来保存游戏玩家的状态信息:
class PlayerMemento {
public:
PlayerMemento(int l,int s,int p);
~PlayerMemento();
int getSpeed();
void setSpeed(int s);
int getLife();
void setLife(int l);
int getPower();
void setPower(int p);
private:
int _speed;
int _life;
int _power;
};
PlayerMemento::PlayerMemento(int l, int s, int p) {
_life = l;
_power = p;
_speed = s;
}
PlayerMemento::~PlayerMemento() {
}
int PlayerMemento::getSpeed() {
return _speed;
}
void PlayerMemento::setSpeed(int s) {
_speed = s;
}
int PlayerMemento::getLife() {
return _life;
}
void PlayerMemento::setLife(int l) {
_life = l;
}
int PlayerMemento::getPower() {
return _power;
}
void PlayerMemento::setPower(int p) {
_power = p;
}
应该还需要一个第三方的状态保存类,专门用来保存游戏玩家的状态。
class MementoManager {
public:
MementoManager();
void saveMemento(PlayerMemento* m);
PlayerMemento* getMemento();
private:
PlayerMemento* _memento;
};
MementoManager::MementoManager() {
}
void MementoManager::saveMemento(PlayerMemento* m) {
_memento = m;
}
PlayerMemento* MementoManager::getMemento() {
return _memento;
}
还需要把游戏玩家添加上一个功能,什么功能?就是产生当前状态和保存当前转态的功能,继续完善游戏玩家。
class Player {
public:
Player();
~Player();
void play();
//受到攻击
void attacked();
void getStateInfo();
PlayerMemento* createMemeto();
void restoreMemeto(PlayerMemento* m);
private:
int _speed = 100;//初始化速度值
int _life = 100;//初始化生命值
int _power = 100;//初始化力量值
};
Player::Player() {
}
Player::~Player() {
}
void Player::play() {
printf("开始游戏\n");
}
void Player::attacked() {
printf("受到攻击! - ");
_speed -= 20;
_life -= 20;
_power -= 20;
}
void Player::getStateInfo() {
printf("当前的生命值:%d 速度值:%d 力量值:%d\n", _life, _speed, _power);
}
PlayerMemento* Player::createMemeto() {
PlayerMemento*m = new PlayerMemento(_life, _speed, _power);
return m;
}
void Player::restoreMemeto(PlayerMemento* m) {
_life = m->getLife();
_speed = m->getSpeed();
_power = m->getSpeed();
}
到现在为止,所需要的类已经完成了,看看客户端如何调用呢?
int main() {
Player* player = new Player;
player->play();
player->getStateInfo();
//受到第一次攻击
player->attacked();
player->getStateInfo();
//受到第一次攻击后,保存当前的状态
MementoManager* manager = new MementoManager;
manager->saveMemento(player->createMemeto());
//受到第二次攻击
player->attacked();
player->getStateInfo();
//捡到神奇的要素,生命值恢复一些,恢复到第一次攻击之后的状态
player->restoreMemeto(manager->getMemento());
player->getStateInfo();
return 0;
}
运行结果:
保存多次状态
上面实现的是只保存一次状态的情况,那么如何保存多次不同状态呢?保存多次不同的状态,需要把不同状态设置一个标志,恢复的时候可以通过相应的标志恢复到不同的状态。
class MementoManager2 {
public:
MementoManager2();
void saveMemento(std::string flag,PlayerMemento* m);
PlayerMemento* getMemento(std::string flag);
private:
std::map<std::string, PlayerMemento*> _mapState;//使用这个容器map来保存不同的状态
};
MementoManager2::MementoManager2() {
}
void MementoManager2::saveMemento(std::string flag, PlayerMemento* m) {
_mapState[flag] = m;
}
PlayerMemento* MementoManager2::getMemento(std::string flag) {
return _mapState[flag];
}
客户端如何调用呢?
int main() {
Player* player = new Player;
player->play();
player->getStateInfo();
MementoManager2* manager = new MementoManager2;
manager->saveMemento("001", player->createMemeto());
//受到第一次攻击
player->attacked();
player->getStateInfo();
manager->saveMemento("002", player->createMemeto());
//受到第二次攻击
player->attacked();
player->getStateInfo();
manager->saveMemento("003", player->createMemeto());
//受到第三次攻击
player->attacked();
player->getStateInfo();
//捡到一小瓶神奇的药水,游戏玩家恢复到003状态
player->restoreMemeto(manager->getMemento("003"));
player->getStateInfo();
//又捡到一大瓶药水,游戏玩家恢复到初始状态
player->restoreMemeto(manager->getMemento("001"));
player->getStateInfo();
return 0;
}
运行结果:
这样就可以保存不同的状态了,而且还可以根据实际需要恢复到不同的状态。
备忘录模式的优点:
1.在不暴露对象的内部状态的情况下,实现了对状态的保存;
2.可以在任何时刻把对象恢复到任一状态。