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

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

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

Ответы [ 5 ]

23 голосов
/ 11 января 2012

Трудно поспорить с краткостью в других ответах 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, которые требуют мутации на месте, но когда класс достаточно любезен, чтобы притвориться, что он неизменен, вам действительно следует использовать версию цепочки методов (т. Е. ->).

8 голосов
/ 11 января 2012

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

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

(.. (NutritionFacts.Builder. 240 8) 
    (calories 100)
    (sodium 350)  
    (carbohydrates 27) 
    (build))
3 голосов
/ 11 января 2012

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

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

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

2 голосов
/ 11 января 2012

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

1 голос
/ 13 мая 2017

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

(-> (Caffeine/newBuilder)
      (.maximumSize 10000)
      (.build))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...