Archive
姑且称之为 Archive Mode —— 它合并了 Read 和 Write 两种方法,是的读写非常的对称,大大减少出错概率.
简述
首先它是对读写的数据流的一种封装——假设我们需要把数据写成 binary、yaml 或者 json等,简单的做法就是定义一个IReadandWrite接口,然后分别把它们实现,最后在上层通过 Read 和 Write 两个方法对数据进行读写操作.
这很不错,只是有略微有点麻烦 ——
public interface IWriteAndWrite {}
public class JsonStroge : IWriteAndWrite
{
// 实现了 read 和 write
}
public class Scene
{
public void SaveScene
{
var data = Serialize(SceneData);
JsonStroge.Write(date)
}
public void ReadScene
{
var data = JsonStroge.Read(path);
SceneData = data;
}
}乍一看没什么问题,逻辑很不错,不过我们一定要保证 Read 和 Write 的读写顺序保持一致,这个东西才可以正常运行——因为假设我们实现了 Binary 的读写,它不是基于key-value的机制,所以一定要按照指针的偏移一步一步的往下走.假设此时读写顺序不一致,那么整个结构就会乱掉.
所以提出了 Archive 机制 —— 保证了读写的高度一致性,来极大的减少 bug 的出现.并且上层不需要关心读写,之需要执行一个 Transfer 即可 —— 也就是关心“我要存什么”(数据),而不是“我要怎么存”(操作).上层就再也不需要显示的调用 Write 或者 Read 方法,比较简洁.
这样整个逻辑就从 “ 命令式 ” 转移到了 “ 声明式 ”
下面来个最简的 Archive 逻辑
enum class ArchiveMode { Read, Write };
class IArchive
{
public:
virtual void Transfer(const char* name, int& value) = 0;
virtual void Transfer(const char* name, float& value) = 0;
}
class JsonArchiveReder : public IArchive
{
// 实现了 int float 等的从磁盘读取
}
class JsonArchiveWriter : public IArchive
{
// 实现了 各种类型 的从读盘读取
}
class Serializer
{
public:
static void Serialize(IArchive& ar, void* instance, const Reflection::ClassInfo& info)
{
// 根据类型分发
if (field.typeName == "int")
ar.Transfer(fieldName, *static_cast<int*>(fieldPtr));
else if (field.typeName == "float")
ar.Transfer(fieldName, *static_cast<float*>(fieldPtr));
}
}
class Scene
{
public:
void SaveScene()
{
JsonArchiveWriter writer;
const auto* goInfo = Reflection::TypeRegister::Instance().GetClass("GameObject");
// 之需要序列化进去就行,因为底层调用的是 Json
Serializer::Serialize(writer, go, *goInfo);
}
void RestoreScene()
{
JsonArchiveReader reader();
Serilizer::Serialize(reader, go, *goInfo);
}
}接着如果想要使用二进制读写,之需要把 JsonArchiveReader 和 JsonArchiveWriter 分别替换成 BinaryArchiveReader 和 BinaryArchiveWriter 就好,上层逻辑不用变化,只需要正确实现 Binary 的读写就好.
这样,把读写操作下沉到IArchive中,而业务层只需要关心数据即可,显得更整洁.
当然,上述只是描述一个数据流的过程,如果在生产实践中,我们还需要引入一个磁盘读写层给上层调用来实现持久化.
cereal 分析
最后贴下 Unreal Archive 以供学习