Вопрос

Я только что прочитал предварительную презентацию 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, настоятельно рекомендует использовать Строитель, когда у вас есть конструктор с множеством аргументов. Одна из причин заключается в том, что он может быть написан так, чтобы гарантировать, что построенный объект всегда находится в согласованном состоянии. Это также позволяет избежать сложных «телескопических конструкторов»; в классе построенного объекта. Еще одна проблема заключается в том, что если вы хотите, чтобы встроенный объект был неизменным (например, для обеспечения безопасности потоков), он не может иметь методов установки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top