没有专门的DSL模板 - 你只需要使用语言中提供的工具,并尝试使其尽可能方便和贴近领域。Lisp比其他语言提供了更多的工具。
一个很好的DSL的具体例子是
ClojureQL。最初,SQL被创建为关系数据库的DSL。从控制台工作非常方便...但在像Java或Clojure这样的编程语言中却不是。Java带有大型ORM框架,如Hibernate,而Clojure提供了简单的DSL,与原始SQL一样方便,但完全作为语言的一部分运行。
(select (table :users) (where (= :id 5)))
在Lisp DSL中常见的事情是使用像
defsomething
这样的构造。例如,在一本书中(抱歉,我不记得它的名字了),有一个文本模式匹配的例子。作者创建了一个模块,其中包含多个匹配器,如用于一个单词的
?
,用于一个或多个单词的
+
,用于零个或多个单词的
*
等。为此,他创建了宏
defmatcher
,该宏需要一些语法,并将此语法的处理程序添加到中央注册表中。这只是抽象概念-他引入了单个宏来告诉他实际想要做什么-定义匹配器,而不是进行几次重复操作。此示例还同时使用了宏和高阶函数。
所以,再次强调,在基于Lisp的DSL中没有什么特别的-您只需使用语言中提供的工具来描述领域区域,无论是Java、Clojure还是其他任何语言。只需熟悉语言功能,您就会看到它应该是什么样子。
UPD. 一些“现实世界”的例子,其中基于Lisp的DSL比面向对象编程更方便:
领域:汽车销售
(defcar my-cool-car :wheels 4, :doors 2, :color red)
(def car1 (make-car my-cool-car))
领域:计费系统
(transaction ;; in Java you cannot create wrapping constructs
(withdraw account1 100) ;; so you have to use inheritance, annotations, etc.
(put account2 100)) ;; which is much more code
领域:一些网络服务,处理多种类型的请求
(defhandler :show-all (fn [params] ...))
(defhandler :find-best (fn [params] ...))
...
(defn handle [message]
(let [msg-type (:type message), msg-params (:params message)]
(if (contains? *handlers* msg-type)
((*handlers* msg-type) msg-params)
(throw (Exception. (concat "No handler for type" (:type message)))))))
这些例子并没有什么特别之处 - 您可以在Java或任何其他语言中实现它们。尽管,关键字(第一个例子)、高阶函数(第二个例子)、宏(所有三个例子)等内容可以使您的代码更加简洁和描述性。