我有一个由几个模块组成的游戏。
其中之一是数据库模块。我想把它做成这样:
Database{
public:
save(&Object); //all my classes in the all modules inherit from Object
load(&Object);
};
使该模块独立于其他模块的最佳方法是什么(其他模块将使用save
和load
函数在Database
中存储数据)?
我考虑的解决方案很少:
- 所有对象都有类似
serialize()
的方法,它继承自Object
类(类似于Java)。Database
使用该方法获取并保存字符串。明显的缺点是:所有对象都必须实现新的方法,并且保存字符串不是最佳的(不知道类的结构) - 为所有类制作"清单"(例如,在将发送到
Database
的文本文件中)。该清单将描述类的结构(例如,一个字符串、两个double、一个罕见使用int)。缺点是灵活性——更改其他模块中的类会对清单产生影响 - 所有类都有自己的
save
和load
方法,Database
使用它们。我不想要它,因为所有的类都必须知道数据库类型,save
和load
应该在Database
类中,而不是分布在整个代码中(这是制作这样一个模块的要点) Database
知道所有其他模块(并且知道如何保存所有对象)。糟糕的是有很多依赖关系。任何模块的更改都会影响Database
哪种方式好?或者也许还有更好的选择?
我遇到的一个解决方案是让所有Object子类实现virtual void serialize(ISerializer& serializer)
方法。
ISerializer将有纯虚拟方法,如void onInt(int value)
、void onString(const char* string)
等,由对象子类在其serialize()
-方法中调用。您的数据库模块可以在两个独立的类中实现ISerializer,DatabaseReader和DatabaseWriter。稍后,您可以添加ObjectInspectionFileDumper、OnScreenObjectStateDebugger或NetworkWriter,它们也实现ISerializer但在其他模块中。每个对象只需要实现serialize()
-方法一次,就可以获得所有扩展的可能性。
优点:
- 只要不读取没有某种版本控制方案的旧版本对象的数据,读写就可以保证匹配
- 这是一种正交设计,其中Object类型和Serializer类型的数量可以相互独立地增长
缺点:
- 主要是一些虚拟函数开销,如果这对您的项目来说是个问题的话。不过,这不是你在常规游戏中通常会做的事情
稍后,您可能会遇到想要调用不想序列化的对象的东西,然后将其分离到一个ISerializable接口类中是有意义的,该接口类仅包含纯虚拟serialize()
-方法。为了适应重要的序列化程序(如调试序列化程序),您可能需要改为void onInt(const char* name, int value)
等。
HTH-