我有一个序列化接口,旨在为我的应用程序封装 XML/JSON/二进制序列化之间的差异。它看起来像这样:
interface Serialization {
bool isObject();
int opApply(int delegate(string member, Serialization value) del); //iterate object
...
int toInt(); //this part is ugly, but without template member overloading, I
long toLong(); //figure out any way to apply generics here, so all basic types
... //have a toType primitive
string toString();
}
class JSONSerialization : Serialization {
private JSON json;
...
long toLong() {
enforce(json.type == JSON_TYPE.NUMBER, SerializationException.IncorrectType);
return cast(long)json.toNumber();
}
...
}
因此,我随后设置的是一组用于注册类型反序列化器并调用它们的模板:
...
registerTypeDeserializer!Vec3(delegate Vec3(Serialization s) {
return Vec3(s[0].toFloat, s[1].toFloat, s[2].toFloat);
});
...
auto v = parseJSON("some file").deserialize!Vec3;
...
registerTypeDeserializer!Light(delegate Light(Serialization s) {
return new Light(s["intensity"].toFloat, s["position"].deserialize!Vec3);
});
这适用于结构和简单类,并且使用新的参数标识符元组和参数默认值元组,我什至应该能够添加自动反序列化器生成。但是,我不太喜欢基本类型和用户定义类型之间的不一致,更重要的是,复杂类型必须依赖全局状态来获取引用:
static MaterialLibrary materials;
registerTypeDeserializer!Model(delegate Model(Serialization s) {
return new Model(materials.borrow(s["material"].toString), ...);
});
那是它真正崩溃的地方。因为我不能(没有寄存器反序列化器函数的扩散)将其他参数传递给反序列化器,所以我很难避免丑陋的全局工厂。我考虑过消除反序列化模板,并为每个用户定义的类型要求一个反序列化函数(它可以接受多个参数),但这对于例如 POD 结构来说似乎需要做很多工作。
那么,我怎样才能简化这个设计,并希望避免大量的样板反序列化器,同时仍然允许我适当地注入对象工厂,而不是全局分配它们?