通过双接口和内置类实现一个相对安全的备忘录模式
封装的更好更安全一点:内置类和双接口
1.建立一个空接口,里面放置一个public空方法,用于给子类实现和调用。
2.给一个需要安全备份的类,然后在其中建立一个内置类(类中类,内置类可以访问外部类的内容,和类函数具有相同权限),并使这个内置类继承空接口,实现自己的业务逻辑(保存状态),确保外部类的备份业务是通过内置类实现的,
3.内置类全部设置为private,以保证除发起者外任何其他类都访问不到,
4.内置类通过其空接口(空父类)就可以将自己的指向的内容地址传给外部,利用的是基类指针可以指向子类内存的功能,同时空基类不具备任何子类中的数据,故保存着基类指针的备忘录管理类无法对内置类中保存的数据进行访问或者修改,
5.备忘录管理类中保存的备忘录指针可以通过发起类提供的内置类强制转换转换为发起类可解析的状态内容。
类图摘自设计模式之禅:
解析:
为什么要再创个类:因为要靠一个数据类来保存发起类的数据。
为什么要将其内置:因为设定上这个备份类只为发起类服务,其他类与其不应该有任何业务往来。
为什么要用private:一是防止外部类通过内置类解析其备份,二是防止子类通过内置类解析其备份。
为什么要内置类要继承一个接口类:为了方便备忘录管理类统一管理备份。
为什么接口类需要是空的:具体的备份类依靠强制类型转换从备忘录管理类中获得备份,如果接口类非空在转换时就有隐患。
什么是双接口:发起类本身对其所属的子系统提供了功能接口(宽接口),发起类对其所属子系统外的模块(容器)提供了接口(窄接口,空的,一般就是给容器访问),由于窄接口中没有提供任何处理数据的方法,因此比较安全。
代码示例:通过内置类与双接口实现的安全性高的备忘录模式
//数据备份类基类,用于给备份管理类保存
class IMemento {};
//备份管理类
class CareTakerOfOriginator
{
public:
void SetMemento(IMemento * memento)
{
mMemento = memento;
}
IMemento* GetMemento()
{
if (mMemento != nullptr)
{
return mMemento;
}
else
{
return nullptr;
}
}
protected:
IMemento* mMemento;
};
//备份发起和调用类
class Originator
{
public:
Originator()
{
mData = 0;
}
void StatusShow()
{
cout << "我现在的数据状态是,数据Data值为" << mData << endl;
}
IMemento* SetMemento()
{
cout << "状态已存盘" << endl;
return (new Memento(mData));
}
void GetMemento(IMemento* memento)
{
//通过数据类型转换将基类指针转变为自己独有的备份指针
Memento* mMemento = reinterpret_cast<Memento*>(memento);
cout << "状态已读取" << endl;
mData = mMemento->GetData();
}
void action()
{
cout << "数据状态发生改变" << endl;
++mData;
}
protected:
int mData;
private:
//数据备份类,设置为private后外部和子类就都无法使用它强制转换了
class Memento :public IMemento
{
public:
//这里需要是public,否则Originator就没办法调用它了。
Memento(int iData)
{
mData = iData;
}
int GetData()
{
return mData;
}
private:
int mData;
};
};
void func()
{
Originator* ZhangSan = new Originator();
CareTakerOfOriginator* ZSCareTaker = new CareTakerOfOriginator();
ZhangSan->StatusShow();
ZSCareTaker->SetMemento(ZhangSan->SetMemento());
ZhangSan->action();
ZhangSan->StatusShow();
ZhangSan->action();
ZhangSan->StatusShow();
ZhangSan->action();
ZhangSan->StatusShow();
ZhangSan->action();
ZhangSan->StatusShow();
ZhangSan->action();
ZhangSan->StatusShow();
ZhangSan->GetMemento(ZSCareTaker->GetMemento());
ZhangSan->StatusShow();
}
int main()
{
func();
return 0;
}
运行结果比较上次的备忘录模式并没有什么变化,同样是实现了保存和读取的功能,
但设计模式并不是面向对象和结果,而面向业务和过程的,
在使用了双接口和内置类后,我们可以看到,除了发起者类Originator,其余任何类都将无法访问到他的备份的内容,即便是备份管理类也没那能力访问,而只能保管下备份类接口,这几乎保证了备份的安全性,但别有用心的人可能不会从备份下手,而从保存备份和获取备份的角度下手,因此安全只是相对,使用了内置类和双接口后,这个备份录比不使用的时候安全多了,它即难以杯外部人员修改,也防止了被项目内的菜鸟无意间破坏。