Добавление ключевого ключевого слова Java в рабочий метод, который создает экземпляры внутри цикла - PullRequest
0 голосов
/ 10 декабря 2018

Возьмите следующие POJO:

public class Widget {
    private String fizz;
    private Long buzz;
    private List<Fidget> collaborators;

   // Constructor, getters & setters
}

public class Fidget {
    private String fizz;
    private String foo;

    // Constructor, getters & setters
}

И следующий (рабочий) метод:

public void compriseWidgets(List<Fidget> fidgetList) {
    List<Widget> widgets = new ArrayList<Widget>();
    Widget currentWidget = null;

    for (Fidget fidget : fidgetList) {
        if (currentWidget == null || 
                !currentWidget.getFizz().equals(fidget.getFizz())) {

            currentWidget = new Widget();
            widgets.add(currentWidget);
            currentWidget.setFizz(fidget.getFizz());
            currentWidget.setBuzz(fidget.getFoo().length());
        }

        currentWidget.getCollaborators().add(fidget);
    }

    return widgets;
}

Здесь мы хотим вернуть List<Widget> и заполнить только этот список:

  1. С первого Fidget в списке ввода (отсюда currentWidget == null);и
  2. Если Fidget и currentWidget имеют одинаковое значение fizz

Кроме того, мы хотим продолжать добавлять collaborators к currentWidget независимо от того,совпадения или нет.

Моя проблема

Новое руководство по стилю кода требует, чтобы мы объявили ALL переменных с final ... то есть мне нужно получитьприведенный выше код изменен так, чтобы выглядеть следующим образом:

public void compriseWidgets(final List<Fidget> fidgetList) {
    final List<Widget> widgets = new ArrayList<Widget>();
    final Widget currentWidget = null;

    for (final Fidget fidget : fidgetList) {
        ...
    }

    return widgets;
}

Поскольку он требует как создания нового Widget внутри цикла, так и внешней (вне цикла) ссылки наWidget, к которому мы можем добавить collaborators, я в полном недоумении, как переписать это с final.Есть идеи?Кроме того, пожалуйста, обратите внимание, что это не то, что я могу «оттолкнуть», мне просто нужно разобраться и заставить его работать с новым стандартом кодирования.

Ответы [ 2 ]

0 голосов
/ 10 декабря 2018

Чтобы расширить мой комментарий, вы можете преобразовать пример кода более или менее механически, например так:

public List<Widget> compriseWidgets(final List<Fidget> fidgetList) {
    final List<Widget> widgets = new ArrayList<Widget>();
    final Widget[] currentWidget = new Widget[] {null};

    for (final Fidget fidget : fidgetList) {
        if (currentWidget[0] == null || 
                !currentWidget[0].getFizz().equals(fidget.getFizz())) {

            currentWidget[0] = new Widget();
            widgets.add(currentWidget);
            currentWidget.setFizz(fidget.getFizz());
            currentWidget.setBuzz(fidget.getFoo().length());
        }

        currentWidget.getCollaborators().add(fidget);
    }

    return widgets;
}

Многие переменные могут быть сделаны final без какого-либо особого влияния, включая списки Fidgetsи виджеты, и переменная цикла в расширенном цикле for.Единственная другая переменная в исходном методе была currentWidget, которую изменяет реализация.Это можно заменить массивом (final) длины 1, нулевой элемент которого можно затем использовать в качестве замены для замены исходной переменной.

Более сложным требованием в тех же строках будетчто вы не можете использовать операторы присваивания (инициализаторы в объявлениях переменных не считаются «присваиваниями»).Это подталкивает к более функциональному стилю программирования, который, как я полагаю, может быть целью вашего нового руководства.Тогда вы можете подойти к этому примерно так:

public List<Widget> compriseWidgets(final List<Fidget> fidgetList) {
    final List<Widget> widgets = new ArrayList<Widget>();
    final ListIterator<Fidget> fidgets = fidgetList.listIterator();

    while (addWidget(widgets, fidgets)) { /* empty */ }

    return widgets;
}    

private boolean addWidget(final List<Widget> widgets, final ListIterator<Fidget> fidgets) {
    if (fidgets.hasNext()) {
        final Fidget firstFidget = fidgets.next();
        final Widget currentWidget = new Widget();

        widgets.add(currentWidget);
        currentWidget.setFizz(firstFidget.getFizz());
        currentWidget.setBuzz(firstFidget.getFoo().length());
        currentWidget.getCollaborators().add(firstFidget);

        while (fidgets.hasNext()) {
            final nextFidget = fidgets.next();

            if (currentWidget.getFizz().equals(nextFidget.getFizz())) {
                currentWidget.getCollaborators().add(nextFidget);
            } else {
                fidgets.previous();
                return true;
            }
        }
    }

    return false;
}

Это почти та же самая уловка, чуть менее очевидная.Изменяемое состояние скрыто в стеке вызовов (каждый вызов addWidget() заменяет мутацию исходного метода currentWidget()) и в объекте контейнера, на этот раз ListIterator.

Можно было быидти дальше в направлении функционального программирования.В общем, например, вы могли бы взглянуть на потоковые подходы, хотя я не думаю, что в данном конкретном случае это работает совершенно чисто.Однако более общее функциональное программирование не имеет ограничений, применимых к потокам.

0 голосов
/ 10 декабря 2018

Шаблон проектирования Builder - отличный способ создания неизменных объектов.Источник: https://stackoverflow.com/a/15461337/4245294

Что мне нравится в этой версии этого шаблона проектирования, так это то, что он дает вам идеальное место для правил проверки до создания объекта.

Пример примененияк этой проблеме:

public class Widget {
    private final String fizz;
    private final Long buzz;
    private final List<Fidget> collaborators;

    private Widget(Builder builder) {
        this.fizz = builder.fizz;
        this.buzz = builder.buzz;
        this.collaborators = builder.collaborators;
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {
        private String fizz;
        private Long buzz;
        private List<Fidget> collaborators = new ArrayList<>();

        public Builder addFizz(String fizz) {
            this.fizz = fizz;
            return this;
        }

        public Builder addBuzz(Long buzz) {
            this.buzz = buzz;
            return this;
        }

        public Builder addCollaborators(List<Fidget> fidgets) {
            collaborators.addAll(fidgets);
            return this;
        }

        public Builder addCollaborator(Fidget fidget) {
            collaborators.add(fidget);
            return this;
        }

        private void validate() throws InvalidArgumentException{
            ArrayList<String> invalidArguments = new ArrayList<>();
            boolean failedValidation = false;
            if (collaborators.isEmpty()) {
                invalidArguments.add("collaborators");
                failedValidation = true;
            }
            if (this.fizz == null) {
                invalidArguments.add("fizz");
                failedValidation = true;
            }
            if (this.buzz == null) {
                invalidArguments.add("buzz");
                failedValidation = true;
            }
            if (failedValidation) {
                throw new InvalidArgumentException(invalidArguments.toArray(new String[0]));
            }
        }

        public Widget build() {
            validate();
            return new Widget(this);
        }
    }
}

И вы создаете действительный объект Widget, например, так:

Widget widget = Widget.builder().addFizz("test").addBuzz(999).addCollaborators(fidgets).build();

Ваш метод compriseWidget имеет проблемы, о которых я упоминал в комментарии к Вопросу, в противном случаеЯ хотел бы привести пример для этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...