Подтвердить что ты не робот

Как создать Java-подобный объект в Clojure, который использует шаблон построителя?

Используя Clojure, как мне создать следующий объект? Объект взят из java-кода (From Effective Java):

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

4b9b3361

Ответ 1

Несмотря на то, что в других ответах с консигментом трудно ответить 1.. несколько отпал в пользу, заменил более универсальный ->. Лично я предпочитаю:

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

Это еще несколько персонажей, но вы получаете две вещи:

  • Ясность. Я могу посмотреть на натриевую линию (например) и сказать ей вызов метода Java, потому что там есть ..
  • Гибкость. Если мне нужно, я могу связать какой-то вызов не-метода в середине (печатать его на stdout, скажем), или в конце всего этого передать его другому вызову функции.

Самое главное, что каждый другой ответ на этот вопрос получил неправильное имя класса: Java NutritionFacts.Builder - это язык сахара над реальным классом JVM с именем NutritionFacts $Builder, и этот класс должен соответствовать Clojure (поскольку мы не используют javac для компиляции нашего кода).

1 Я не согласен с предложением doto: он работает только потому, что этот класс Builder реализует свою цепочку методов, изменяя один экземпляр и затем возвращая его. doto отлично подходит для объектов Java, для которых требуется мутация на месте, но когда класс достаточно любезен, чтобы притворяться неизменным, вы действительно должны использовать версию метода-цепочки (т.е. ->).

Ответ 2

Используйте макрос ... Это две последовательные точки. Он позволяет только то, что вам нужно - последовательно вызвать следующий метод Java в результате предыдущего.

У меня нет REPL вокруг, но ваша строка должна перевести на что-то вроде:

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

Ответ 3

Я только начинаю с Clojure, но он выглядит как вызов стандартного метода для меня:

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

EDIT:
Как указывает @Goran Jovic, это вызывает все методы для объекта, созданного в первой форме.
Таким образом, он работает в этом случае, поскольку код Java использует цепочку методов, но не является более общеприменимым.

Ответ 4

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

Ответ 5

Этот поток пару лет, и макрос нити-первого по-прежнему предпочтительнее, насколько я могу сказать, но синтаксис $не нужен. Слэш (/) работает также:

(-> (Caffeine/newBuilder)
      (.maximumSize 10000)
      (.build))