Цепной вызов в Java 7?
-
06-07-2019 - |
Вопрос
Я только что прочитал предварительную презентацию Java 7 (pdf) , и была слайд Цепной вызов . Вот пример, используемый на слайде:
// Construction with setters
DrinkBuilder margarita = new DrinkBuilder();
margarita.add("tequila");
margarita.add("orange liqueur");
margarita.add("lime juice");
margarita.withRocks();
margarita.withSalt();
Drink drink = margarita.drink();
// Construction with chained invocation
Drink margarita = new DrinkBuilder()
.add("tequila")
.add("orange liqueur")
.add("lime juice")
.withRocks()
.withSalt()
.drink();
И у меня смешанные чувства по этому поводу. Не следует объединять слишком много вызовов методов в одно утверждение. С другой стороны, написание margarita.this ()
и margarita.that ()
также не слишком удобно.
Теперь я приезжаю на Яву из мира Delphi. А в Delphi есть с
языковая конструкция. Это лелеют немногие и ненавидят многие (или наоборот?). Я нахожу с
более элегантным, чем идея цепного вызова (который, я считаю, работает на основе метода void
, возвращающего ссылку на объект, для которого он был вызван), и эта часть мне не нравится, так как void
должен возвращать ничего ).
Я был бы признателен за возможность использования языка with
в Java, поэтому пример кода можно написать так:
Drink margarita = null;
with (new DrinkBuilder()) {
add("tequila");
add("orange liqueur");
add("lime juice");
withRocks();
withSalt();
margarita = drink();
}
Я единственный, кто предпочел бы это решение цепочному вызову? Кто-нибудь еще считает, что with
может быть полезным расширением языка Java? (Напоминает мне о чьем-то вопросе о необходимости "Java ++" ...)
Решение
оператор with может быть переведен в Java с использованием анонимных классов с инициализатором:
Drink margarita = new DrinkBuilder() {{
add(“tequila”);
add(“orange liqueur”);
add(“lime juice”);
withRocks();
withSalt();
}}.drink();
Недостатки использования этой идиомы хорошо документированы здесь . р>
Цепной вызов - это псевдоним метода. Это хорошо известная идиома, которая работает с любой версией Java:
class Chained {
public Chained withFoo() {
// ...
return this;
}
public Chained withBar() {
// ...
return this;
}
}
предложение для JDK 7: разрешить метод цепочки также для типа возврата void : р>
class ChainedJava7 {
public void withFoo() {
// ...
}
public void withBar() {
// ...
}
}
Другие советы
Это может вас заинтересовать.
Мне очень нравятся с
инструкциями этой формы, но я предпочитаю их VB-версию:
With testObject
.Height = 100
.Text = "Hello, World"
.ForeColor = System.Drawing.Color.Green
End With
Поскольку каждому атрибуту в блоке With
все еще должен предшествовать .
, вы знаете, что вы ссылаетесь на свойство Object, а не, скажем, на локальную переменную , уменьшая любые столкновения пространства имен.
Если мы возьмем ваш пример:
with (new DrinkBuilder()) {
add(“tequila”);
add(“orange liqueur”);
add(“lime juice”);
withRocks();
withSalt();
margarita = drink();
}
нет простого способа определить, является ли withSalt ()
методом DrinkBuilder
или методом в локальном классе. Если вы разрешите только методы объекта с
в блоке with
, то я думаю, что они станут намного менее полезными.
Я не фанат этого использования с
; Я очень предпочитаю Python с
оператором . Я согласен с вами, что void
должно означать void
. В приведенном вами примере, если человек действительно хочет иметь возможность связывать вызовы методов, он должен просто изменить типы возвращаемых данных в своих методах, чтобы они были цепными.
Может быть, множество вызовов одного объекта является признаком того, что некоторый код необходимо перемещать?
Джошуа Блох в Эффективной Java , пункт № 2, настоятельно рекомендует использовать Строитель, когда у вас есть конструктор с множеством аргументов. Одна из причин заключается в том, что он может быть написан так, чтобы гарантировать, что построенный объект всегда находится в согласованном состоянии. Это также позволяет избежать сложных «телескопических конструкторов»; в классе построенного объекта. Еще одна проблема заключается в том, что если вы хотите, чтобы встроенный объект был неизменным (например, для обеспечения безопасности потоков), он не может иметь методов установки.