如何在Clojure中使用构建器模式创建类似Java的对象?

时间:2012-01-11 15:21:05

标签: clojure

使用Clojure,如何创建以下对象?该对象取自java代码(From Effective Java):

NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build();

5 个答案:

答案 0 :(得分:23)

虽然很难与其他答案 1 中的简洁性争论,..有点失宠,取而代之的是更多才多艺的->。我个人更喜欢:

(-> (NutritionFacts$Builder. 240 8) 
    (.calories 100)
    (.sodium 350)  
    (.carbohydrates 27) 
    (.build))

这是另外两个角色,但你获得了两件事:

  • 明晰。我可以查看钠线(例如)并告诉它是一个Java方法调用,因为.就在那里。
  • 灵活性。如果我需要,我可以在中间链接一些非方法调用(将其打印到stdout,比方说),或者在所有这些调用结束时将其输入到其他函数调用中。

最重要的是,这个问题的每个其他答案都让错误的类名:Java的NutritionFacts.Builder是名为NutritionFacts $ Builder的真正JVM类的语言糖,而那个类是Clojure必须引用的类(因为我们不是使用javac编译我们的代码)。

1 我不同意doto建议:它的作用只是因为这个Builder类碰巧通过改变单个实例然后返回它来实现其方法链。 doto非常适合需要就地变异的Java对象,但是当一个类足够假装它是不可变的时,你应该真正使用方法链接版本(即->)。

答案 1 :(得分:8)

使用..宏。这是两个连续的点。它只允许你需要的东西 - 连续调用前一个结果的下一个Java方法。

我没有REPL,但你的行应该转换为:

(.. (NutritionFacts.Builder. 240 8) 
    (calories 100)
    (sodium 350)  
    (carbohydrates 27) 
    (build))

答案 2 :(得分:3)

我只是从Clojure开始,但它看起来像是对我的标准方法调用:

(doto
  (NutritionFacts.Builder. 240 8)
  (.carbohydrates 27)
  (.sodium 35)
  (.calories 100)
  (.build)
)

编辑:
正如@Goran Jovic指出的那样,这会调用以第一种形式创建的对象上的所有方法 因此,它适用于这种情况,因为Java代码使用方法链接,但通常不适用。

答案 3 :(得分:2)

(.. (NutrionalFacts.Builder. 240 8) (calories 100) (sodium 35) (carbohydrates 27) (build))

答案 4 :(得分:1)

这个线程已经有几年了,据我所知,线程优先宏仍然是首选方式,但不需要$语法。 斜杠(/)也起作用:

{{1}}