实用模式:内部域特定语言
2010-09-30 22:42:30 来源:WEB开发网在实施时,将“new TimeSpan(2, 0, 0, 0)”转换为“2.Days()”可能没多大区别,但是哪个可读性更好?我自己在将业务规则转换为代码时,更愿意表达为两天,而不是“时间间隔为两天零小时零分”。代码版本可读性越高,则更易于浏览进行纠正,这就是我使用文本表达式版本的充分理由。
语义模型
构建新的 DSL 时,我需要解决两个问题。首先,我的团队及我本人问问我们自己,如何以逻辑和自描述的方式来表达 DSL 使其易于使用。就此问题我绞尽脑汁,而没有考虑将如何结构化或构建实际功能。
例如,通过 StructureMap 控制反转 (IoC) 容器工具,用户可以在 StructureMap 的“注册表 DSL”内部显式配置容器,如下所示:
var container = new Container(x =>
{
x.For<ISendEmailService>().HttpContextScoped()
.Use<SendEmailService>();
});
如果您尚不熟悉 IoC 容器的用法,在您看来,代码的所有作用就是,当您要求运行时的容器提供 ISendEmailService 类型的对象时,将获得具体类型为 SendEmailService 的实例。调用 HttpContextScoped 会指示 StructureMap 将 ISendEmailService 对象引入单个 HttpRequest,这意味着如果代码在 ASP.NET 内部运行,每个单个 HTTP 请求都存在一个唯一的 ISendEmailService 实例,而不管您在单个 HTTP 请求内请求 ISendEmailService 的次数。
一旦我想到所需的语法后,则只剩解决关键性的问题:我究竟如何将 DSL 语法与实现实际行为的代码联系起来。您可以将行为代码直接放到 DSL 代码中,以便运行时操作可以直接在 Expression Builder 对象中进行,但我强烈建议您除非在非常简单的情况下,否则不要这样做。在某种程度上,很难对 Expression Builder 类进行单元测试,并且通过单步执行 fluent 界面来调试此类不利于工作效率或运行状况。如果您非常希望能够进行单元测试,则需要对 DSL 的运行时行为元素进行调试和故障排除,而不必在典型的 fluent 界面中单步调试所有代码间接寻址。
更多精彩
赞助商链接