Clojure中的DSL替代面向对象软件解决方案?

6

我想知道是否有一个具体的Clojure领域特定语言(DSL)的例子,可以替代一个好的面向对象程序(比如Java)的抽象和可读性。

我一直在尝试将一个面向对象的数据模型(基于“bean”,具有非常抽象的方法,隐藏底层实现)转换成Clojure代码。

我知道“宏”和“高阶函数”存在,但是我从未见过它们应用于一个真实世界的数据集,这个数据集易于理解(例如课程注册系统、汽车经销商、计费系统或类似的东西,回想一下Hibernate和Ibatis在上个十年中广泛使用的臭名昭著的“JPetStore”示例)。

是否存在任何领域特定模板,可用于学习如何使用协议和高阶函数来建模Clojure中的真实世界系统?

3个回答

4
没有专门的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) ;; in Java you need Factory
(def car1 (make-car my-cool-car))                    ;; and lots of methods to 
                                                     ;; add features to cars and 
                                                     ;; cars to factory

领域:计费系统

(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] ...))     ;; adds defined function to the
(defhandler :find-best (fn [params] ...))    ;; map of :message-type -> function
...
(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或任何其他语言中实现它们。尽管,关键字(第一个例子)、高阶函数(第二个例子)、宏(所有三个例子)等内容可以使您的代码更加简洁和描述性。


1

我不确定这是否是您正在寻找的内容,但我读过一本关于Clojure的书(Programming Clojure; Pragmatic Programmers),其中包含一个漂亮小巧的DSL示例。您可以在https://github.com/stuarthalloway/lancet找到代码。基本上,lancet类似于makeant,但作为Clojure-DSL实现。


Lancet是一种DSL,但它并不是一个真正的“现实世界”问题,因为大多数程序员从未尝试过编写这样的系统:看看那个老旧的Google JPetStore应用程序... - jayunit100

1

OOP(面向对象编程)很好,因为我们非常习惯它,并且它可以映射到现实世界的概念。

你可以看到如何用地图和多方法(类似于 JS 中的原型继承)构建一个 OOP 系统,在《Clojure 之乐》第 9 章中有介绍。

Paul Graham 的 Lisp 书籍展示了如何在 Lisp 中创建对象系统。将其适应到 Clojure 应该很容易。

该书还广泛解释了“自下而上”编程,即构建基本模块并将它们组合起来构建更高级别结构。

此外,如果您可以在许多应用程序(如 Java 宠物商店)中看到主要概念是过程/函数式的;他们不广泛使用像一般化或封装之类的对象概念。

Bean 没有行为。没有封装的数据具有 getter / setter,允许公共访问它们。对于它所提供的内容,您可以在类型语言中使用 C 结构体或在动态语言(如 Clojure)中使用 Map。

对它们工作的服务基本上是函数。它们没有状态,并从参数(bean)或数据库中取得数据。如果您真的需要接口,则在 Clojure 中有协议。

这并不那么复杂。

像在 Java 中一样为您的 Bean 命名... 但将它们实现为 Clojure Map 或记录。

为您的服务命名并将其实现为函数。

需要工厂?创建接受配置并返回函数的函数。

需要依赖注入?那么您可以使用函数参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接