目录
16. 备忘录模式
备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原来保存的状态。
备忘录模式中需要定义的角色类:
1. Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。Originator可以根据需要决定Memento存储自己的哪些内部状态。
2. Memento(备忘录):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。
3. Caretaker(管理者):负责备忘录Memento,不能对Memento的内容进行访问或者操作。
/*
* 关键代码:Memento类、Originator类、Caretaker类;Originator类不与Memento类耦合,而是与Caretaker类耦合。
*/
#include <iostream>
using namespace std;
//需要保存的信息
typedef struct
{
int grade;
string arm;
string corps;
}GameValue;
//Memento类
class Memento
{
public:
Memento(){}
Memento(GameValue value):m_gameValue(value){}
GameValue getValue()
{
return m_gameValue;
}
private:
GameValue m_gameValue;
};
//Originator类
class Game
{
public:
Game(GameValue value):m_gameValue(value)
{}
void addGrade() //等级增加
{
m_gameValue.grade++;
}
void replaceArm(string arm) //更换武器
{
m_gameValue.arm = arm;
}
void replaceCorps(string corps) //更换工会
{
m_gameValue.corps = corps;
}
Memento saveValue() //保存当前信息
{
Memento memento(m_gameValue);
return memento;
}
void load(Memento memento) //载入信息
{
m_gameValue = memento.getValue();
}
void showValue()
{
cout << "Grade: " << m_gameValue.grade << endl;
cout << "Arm : " << m_gameValue.arm.data() << endl;
cout << "Corps: " << m_gameValue.corps.data() << endl;
}
private:
GameValue m_gameValue;
};
//Caretaker类
class Caretake
{
public:
void save(Memento memento) //保存信息
{
m_memento = memento;
}
Memento load() //读已保存的信息
{
return m_memento;
}
private:
Memento m_memento;
};
int main()
{
GameValue v1 = {0, "Ak", "3K"};
Game game(v1); //初始值
game.addGrade();
game.showValue();
cout << "----------" << endl;
Caretake care;
care.save(game.saveValue()); //保存当前值
game.addGrade(); //修改当前值
game.replaceArm("M16");
game.replaceCorps("123");
game.showValue();
cout << "----------" << endl;
game.load(care.load()); //恢复初始值
game.showValue();
return 0;
}
16.1 实例2
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态[DP]。
举个简单的例子,我们玩游戏时都会保存进度,所保存的进度以文件的形式存在。这样下次就可以继续玩,而不用从头开始。这里的进度其实就是游戏的内部状态,而这里的文件相当于是在游戏之外保存状态。这样,下次就可以从文件中读入保存的进度,从而恢复到原来的状态。这就是备忘录模式。
给出备忘录模式的UML图,以保存游戏的进度为例。
Memento类定义了内部的状态,而Caretake类是一个保存进度的管理者,GameRole类是游戏角色类。可以看到GameRole的对象依赖于Memento对象,而与Caretake对象无关。下面给出一个简单的是实现。
//需保存的信息
class Memento
{
public:
int m_vitality; //生命值
int m_attack; //进攻值
int m_defense; //防守值
public:
Memento(int vitality, int attack, int defense):
m_vitality(vitality),m_attack(attack),m_defense(defense){}
Memento& operator=(const Memento &memento)
{
m_vitality = memento.m_vitality;
m_attack = memento.m_attack;
m_defense = memento.m_defense;
return *this;
}
};
//游戏角色
class GameRole
{
private:
int m_vitality;
int m_attack;
int m_defense;
public:
GameRole(): m_vitality(100),m_attack(100),m_defense(100) {}
Memento Save() //保存进度,只与Memento对象交互,并不牵涉到Caretake
{
Memento memento(m_vitality, m_attack, m_defense);
return memento;
}
void Load(Memento memento) //载入进度,只与Memento对象交互,并不牵涉到Caretake
{
m_vitality = memento.m_vitality;
m_attack = memento.m_attack;
m_defense = memento.m_defense;
}
void Show() { cout<<"vitality : "<< m_vitality<<", attack : "<< m_attack<<", defense : "<< m_defense<<endl; }
void Attack() { m_vitality -= 10; m_attack -= 10; m_defense -= 10; }
};
//保存的进度库
class Caretake
{
public:
Caretake() {}
void Save(Memento menento) { m_vecMemento.push_back(menento); }
Memento Load(int state) { return m_vecMemento[state]; }
private:
vector<Memento> m_vecMemento;
};
// 客户使用方式:
//测试案例
int main()
{
Caretake caretake;
GameRole role;
role.Show(); //初始值
caretake.Save(role.Save()); //保存状态
role.Attack();
role.Show(); //进攻后
role.Load(caretake.Load(0)); //载入状态
role.Show(); //恢复到状态0
return 0;
}
参考资料:https://blog.csdn.net/wuzhekai1985/article/details/6672906
参考资料:https://www.cnblogs.com/chengjundu/p/8473564.html
17. 中介者模式
中介者模式:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之前的交互。
如果对象与对象之前存在大量的关联关系,若一个对象改变,常常需要跟踪与之关联的对象,并做出相应的处理,这样势必会造成系统变得复杂,遇到这种情形可以考虑使用中介者模式。当多个对象存在关联关系时,为它们设计一个中介对象,当一个对象改变时,只需要通知它的中介对象,再由它的中介对象通知每个与它相关的对象。
/*
* 关键代码:将相关对象的通信封装到一个类中单独处理。
*/
#include <iostream>
using namespace std;
class Mediator;
//抽象同事类。
class Businessman
{
public:
Businessman(){}
Businessman(Mediator* mediator) : m_pMediator(mediator){}
virtual ~Businessman(){}
virtual void setMediator(Mediator* m)
{
m_pMediator = m;
}
virtual void sendMessage(const string& msg) = 0;
virtual void getMessage(const string& msg) = 0;
protected:
Mediator* m_pMediator;
};
//抽象中介者类。
class Mediator
{
public:
virtual ~Mediator(){}
virtual void setBuyer(Businessman* buyer) = 0;
virtual void setSeller(Businessman* seller) = 0;
virtual void send(const string& msg, Businessman* man) = 0;
};
//具体同事类
class Buyer : public Businessman
{
public:
Buyer() : Businessman(){}
Buyer(Mediator* mediator) : Businessman(mediator){}
void sendMessage(const string& msg) override
{
m_pMediator->send(msg, this);
}
void getMessage(const string& msg)
{
cout << "Buyer recv: " << msg.data() << endl;
}
};
//具体同事类
class Seller : public Businessman
{
public:
Seller() : Businessman(){}
Seller(Mediator* mediator) : Businessman(mediator){}
void sendMessage(const string& msg) override
{
m_pMediator->send(msg, this);
}
void getMessage(const string& msg)
{
cout << "Seller recv: " << msg.data() << endl;
}
};
//具体中介者类
class HouseMediator : public Mediator
{
public:
void setBuyer(Businessman* buyer) override
{
m_pBuyer = buyer;
}
void setSeller(Businessman* seller) override
{
m_pSeller = seller;
}
void send(const string& msg, Businessman* man) override
{
if(man == m_pBuyer)
{
m_pSeller->getMessage(msg);
}
else if(man == m_pSeller)
{
m_pBuyer->getMessage(msg);
}
}
private:
Businessman* m_pBuyer;
Businessman* m_pSeller;
};
int main()
{
HouseMediator* hMediator = new HouseMediator;
Buyer* buyer = new Buyer(hMediator);
Seller* seller = new Seller(hMediator);
hMediator->setBuyer(buyer);
hMediator->setSeller(seller);
buyer->sendMessage("Sell not to sell?");
seller->sendMessage("Of course selling!");
delete buyer;
buyer = nullptr;
delete seller;
seller = nullptr;
delete hMediator;
hMediator = nullptr;
return 0;
}
17.1 实例2
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
本文就以租房为例子,如果没有房屋中介,那么房客要自己找房东,而房东也要自己找房客,非常不方便。有了房屋中介机构就方便了,房东可以把要出租的房屋信息放到中介机构,而房客可以去中介机构咨询。
在软件中,就是多个对象之间需要通信,如果没有中介,对象就需要知道其他对象,最坏情况下,可能需要知道所有其他对象,而有了中介对象就方便多了,对象只需与中介对象通信,而不用知道其他的对象。这就是中介者模式,下面以租房为例,给出中介者模式的UML图。
实现不难,下面给出C++的实现:
class Mediator;
//抽象人
class Person
{
protected:
Mediator *m_mediator; //中介
public:
virtual void SetMediator(Mediator *mediator){} //设置中介
virtual void SendMessage(string message) {} //向中介发送信息
virtual void GetMessage(string message) {} //从中介获取信息
};
//抽象中介机构
class Mediator
{
public:
virtual void Send(string message, Person *person) {}
virtual void SetA(Person *A) {} //设置其中一方
virtual void SetB(Person *B) {}
};
//租房者
class Renter: public Person
{
public:
void SetMediator(Mediator *mediator) { m_mediator = mediator; }
void SendMessage(string message) { m_mediator->Send(message, this); }
void GetMessage(string message) { cout<<"租房者收到信息"<<message; }
};
//房东
class Landlord: public Person
{
public:
void SetMediator(Mediator *mediator) { m_mediator = mediator; }
void SendMessage(string message) { m_mediator->Send(message, this); }
void GetMessage(string message) { cout<<"房东收到信息:"<<message; }
};
//房屋中介
class HouseMediator : public Mediator
{
private:
Person *m_A; //租房者
Person *m_B; //房东
public:
HouseMediator(): m_A(0), m_B(0) {}
void SetA(Person *A) { m_A = A; }
void SetB(Person *B) { m_B = B; }
void Send(string message, Person *person)
{
if(person == m_A) //租房者给房东发信息
m_B->GetMessage(message); //房东收到信息
else
m_A->GetMessage(message);
}
};
// 客户使用方式如下:
//测试案例
int main()
{
Mediator *mediator = new HouseMediator();
Person *person1 = new Renter(); //租房者
Person *person2 = new Landlord(); //房东
mediator->SetA(person1);
mediator->SetB(person2);
person1->SetMediator(mediator);
person2->SetMediator(mediator);
person1->SendMessage("我想在XXX路附近租套房子,价格800元一个月\n");
person2->SendMessage("出租房子:XXXXXX,70平米,1000元一个月\n");
delete person1; delete person2; delete mediator;
return 0;
}
参考资料:https://blog.csdn.net/wuzhekai1985/article/details/6673603