Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a Java-like object in Clojure that uses builder pattern?

Tags:

clojure

Using Clojure, how do I create the following object? The object is taken from java code (From Effective Java):

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

like image 705
Rob Buhler Avatar asked Jan 11 '12 15:01

Rob Buhler


People also ask

What is the use of builder pattern in Java?

The builder pattern simplifies the creation of objects. It also simplifies the code as your do not have to call a complex constructor or call several setter methods on the created object. The builder pattern can be used to create an immutable class.

What is the use of builder pattern to create?

Builder pattern aims to “Separate the construction of a complex object from its representation so that the same construction process can create different representations.” It is used to construct a complex object step by step and the final step will return the object.

What is builder pattern in spring boot?

The builder pattern allows you to enforce a step-by-step process to construct a complex object as a finished product. In this pattern, the step-by-step construction process remains same but the finished products can have different representations.

What is a builder function?

What is a builder function? 🤔 A builder is a Flutter design pattern in which the construction code of a widget is defined outside of its class. Builder functions are callback interfaces that pass data (often layout-specific) to the parent widget which returns a child based on that data.


2 Answers

While it's hard to argue with the concision in the other answers1, .. has somewhat fallen out of favor, replaced by the more versatile ->. Personally I prefer :

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

It's a couple more characters, but you gain two things:

  • Explicitness. I can look at the sodium line (for example) and tell it's a Java method call, because the . is right there.
  • Flexibility. If I need to, I can chain some non-method call in the middle there (printing it to stdout, say), or at the end of all this feed it in to some other function call.

Most importantly, every other answer to this question has gotten the classname wrong: Java's NutritionFacts.Builder is language sugar over the real JVM class named NutritionFacts$Builder, and that class is the one Clojure must refer to (since we are not using javac to compile our code).

1 I do disagree with the doto suggestion: it works only because this Builder class happens to implement its method-chaining by mutating a single instance and then returning it. doto is great for Java objects that require in-place mutation, but when a class is kind enough to pretend it's immutable you should really be using the method-chaining version (ie, ->).

like image 127
amalloy Avatar answered Sep 20 '22 08:09

amalloy


Use .. macro. It's two consecutive dots. It allows just what you need - to consecutively call next Java method on the result of the previous.

I don't have a REPL around, but your line should translate to something like:

(.. (NutritionFacts.Builder. 240 8) 
    (calories 100)
    (sodium 350)  
    (carbohydrates 27) 
    (build))
like image 38
Goran Jovic Avatar answered Sep 19 '22 08:09

Goran Jovic