原文地址
作者:h.s.teoh
最近,我需要扩展简单序化
系统,来处理多态
对象.
昨天,我发现个优秀解决方案:用crtp(奇异递归模板)
,来注入方法至继承
类.
class Saveable(Derived, Base) : Base {
static if (is(Base == Object)) {//基类
// 顶级虚函数
void save() { ... }
} else {
//继承类,盖
override void save() { ... }
}
}
class Base : Saveable!(Base, Object) { ... }
class Derived1 : Saveable!(Derived1, Base) { ... }
class Derived2 : Saveable!(Derived1, Base) { ... }
奇异声明
在类的第1行
,很难丢失.可保存
的基
参数,使我们容易注入
盖方法至类层次
,并区别基类/继承类
.
可保存
的保存
方法,用模板
参数来自省
继承类并生成序化
字段代码.在序化输出中它包含生成标识类型的标签的代码
.从而完成了一半序化.
为了解序
,可以用对象.工厂
.但接口
太旧,且从正确类型
中读回字段有断开,因而可以用静态构造器
来修复.
alias Loader = Object function(InputFile);
Loader[string] classLoaders;
class Saveable(Derived, Base) : Base {
static if (is(Base == Object)) {//基类
// 顶级虚函数
void save() { ... }
} else {
//继承类,盖
override void save() { ... }
}
static this()//静态构造器.
{
classLoaders[Derived.stringof] = (InputFile f) {
auto result = new Derived;
... //用自省来读回继承的字段
return result;
};
}
}
这儿神奇的地方是,每个可保存
的实例生成一个静 本()
块,有继承类
的全部编译时信息
.所以函数字面
可用编译时
自省来生成可序化
代码.然后通过以类名
作为键
来注册函数字面
进全局加载表
.(为了简单
,这里我用.的串
,对大规模项目,你可用.的混杂
).
因为,静 本
块在启动程序,加载动态库
时运行.确保启动程序
后类加载器
有程序要用的所有信息
.所以解序代码
可简单在类加载器
中查找保存的类型签
.并调用函数指针
来重构
对象.结果是,为可序化
任何类,你只需要用:
class MyClass : Saveable!(MyClass, MyBase) { ... }
替换:
class MyClass : MyBase { ... }
其他所有全部自动搞好.不需要插件,重复序化类,运行时类型信息
,甚至还支持动态库加载的类定义
.只要你用Runtime.loadLibrary
来确保运行静态构造器
.因为静态构造器
会注入
任何新类加载器至类加载器
.并自动教会解序代码
如何解序
.
奇异模板+编译时自省+静态构造==成功
!