Управление конструкторами со многими параметрами в Java - PullRequest
94 голосов
/ 21 октября 2008

В некоторых наших проектах есть иерархия классов, которая добавляет дополнительные параметры по мере продвижения по цепочке. Внизу, некоторые из классов могут иметь до 30 параметров, 28 из которых просто передаются в супер-конструктор.

Я признаю, что было бы неплохо использовать автоматический DI через что-то вроде Guice, но по некоторым техническим причинам эти конкретные проекты ограничены Java.

Соглашение об организации аргументов в алфавитном порядке по типу не работает, потому что если тип подвергается рефакторингу (круг, который вы передавали в качестве аргумента 2, теперь является формой), он может внезапно выйти из строя.

Этот вопрос может быть конкретным и чреват критикой "Если это ваша проблема, вы делаете это неправильно на уровне проекта", но я просто ищу любые точки зрения.

Ответы [ 8 ]

244 голосов
/ 21 октября 2008

Шаблон проектирования Builder может помочь. Рассмотрим следующий пример

public class StudentBuilder
{
    private String _name;
    private int _age = 14;      // this has a default
    private String _motto = ""; // most students don't have one

    public StudentBuilder() { }

    public Student buildStudent()
    {
        return new Student(_name, _age, _motto);
    }

    public StudentBuilder name(String _name)
    {
        this._name = _name;
        return this;
    }

    public StudentBuilder age(int _age)
    {
        this._age = _age;
        return this;
    }

    public StudentBuilder motto(String _motto)
    {
        this._motto = _motto;
        return this;
    }
}

Это позволяет нам писать код вроде

Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
                 .name("Spicoli")
                 .age(16)
                 .motto("Aloha, Mr Hand")
                 .buildStudent();

Если мы пропустим обязательное поле (предположительно, имя обязательно), тогда мы можем сделать так, чтобы конструктор Student выбросил исключение. И это позволяет нам использовать стандартные / необязательные аргументы без необходимости отслеживать порядок следования аргументов любого типа, поскольку любой порядок этих вызовов будет одинаково хорошо работать.

21 голосов
/ 21 октября 2008

Можете ли вы инкапсулировать связанные параметры внутри объекта?

например, если параметры похожи на


MyClass(String house, String street, String town, String postcode, String country, int foo, double bar) {
  super(String house, String street, String town, String postcode, String country);
  this.foo = foo;
  this.bar = bar;

тогда вы могли бы иметь:


MyClass(Address homeAddress, int foo, double bar) {
  super(homeAddress);
  this.foo = foo;
  this.bar = bar;
}

14 голосов
/ 21 октября 2008

Что вы, вероятно, хотите сделать, это иметь класс Builder. Тогда вы бы сделали что-то вроде этого:

MyObject obj = new MyObjectBuilder().setXxx(myXxx)
                                    .setYyy(myYyy)
                                    .setZzz(myZzz)
                                    // ... etc.
                                    .build();

См. Стр. 8 и далее этой презентации Джоша Блоха (PDF) или этого обзора Effective Java

7 голосов
/ 22 октября 2008

Что ж, использование шаблона построителя может быть решением one .

Но как только вы придете к 20-30 параметрам, я думаю, что между параметрами существует высокая связь. Так что (как и предполагалось) оборачивать их в логически вменяемые объекты данных, вероятно, имеет смысл. Таким образом, объект данных уже может проверить правильность ограничений между параметрами.

Для всех моих проектов в прошлом, когда я пришел к выводу, что слишком много параметров (а это было 8, а не 28!), Я смог дезинфицировать код, создав лучшую модель данных.

4 голосов
/ 21 октября 2008

Поскольку вы ограничены Java 1.4, если вы хотите DI, тогда Spring будет очень неплохим вариантом. DI полезен только в тех местах, где параметрами конструктора являются сервисы или что-то, что не изменяется во время выполнения.

Если у вас есть все эти разные конструкторы из-за того, что вам нужны переменные опции для построения объекта, вам следует серьезно рассмотреть возможность использования шаблона Builder.

4 голосов
/ 21 октября 2008

Лучшее решение - не иметь слишком много параметров в конструкторе. Только параметры, действительно необходимые в конструкторе, являются параметрами, которые необходимы для правильной инициализации объекта. Вы можете иметь конструкторы с несколькими параметрами, а также иметь конструктор только с минимальными параметрами. Дополнительные конструкторы вызывают этот простой конструктор и после этого устанавливают другие параметры. Таким образом, вы можете избежать цепной проблемы с большим и большим количеством параметров, а также иметь несколько конструкторов удобства.

2 голосов
/ 13 июня 2016

Я действительно могу рекомендовать использовать Immutables или POJOBuilder при использовании шаблона компоновщика.

1 голос
/ 21 октября 2008

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

Одна вещь, которую вы могли бы сделать, это сгруппировать некоторые логически сгруппированные параметры в их собственный объект более высокого уровня, но у него есть свои проблемы.

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