Управление конструкторами со многими параметрами в Java
В некоторых наших проектах существует иерархия классов, которая добавляет больше параметров, когда она идет по цепочке. Внизу некоторые классы могут иметь до 30 параметров, 28 из которых просто передаются в супер-конструктор.
Я признаю, что использование автоматизированного DI с помощью чего-то вроде Guice было бы неплохо, но по некоторым техническим причинам эти конкретные проекты ограничены Java.
Соглашение об упорядочивании аргументов по алфавиту по типу не работает, потому что если тип рефакторизуется (круг, который вы проходили для аргумента 2, теперь представляет собой Shape), он может внезапно выйти из строя.
Этот вопрос может быть специфическим и чреватым критикой "Если ваша проблема, вы делаете это неправильно на уровне дизайна", но я просто ищу любую точку зрения.
Ответы
Ответ 1
Шаблон проектирования 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 для исключения.
И это позволяет нам иметь необязательные/необязательные аргументы без необходимости отслеживать какой-либо порядок аргументов, так как любой порядок этих вызовов будет работать одинаково хорошо.
Ответ 2
Можете ли вы инкапсулировать связанные параметры внутри объекта?
например, если параметры похожи на
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;
}
Ответ 3
Что вы, вероятно, хотите сделать, это класс Builder. Тогда вы сделали бы что-то вроде этого:
MyObject obj = new MyObjectBuilder().setXxx(myXxx)
.setYyy(myYyy)
.setZzz(myZzz)
// ... etc.
.build();
См. стр. 8 и ниже это презентация Джоша Блоха (PDF) или этот обзор Эффективной Java
Ответ 4
Ну, использование шаблона построителя может быть одним из решений.
Но как только вы придете к 20-30 параметрам, я бы предположил, что между параметрами существует высокая взаимосвязь. Таким образом (как и предполагалось), обертывание их в логически разумные объекты данных, вероятно, имеет наибольший смысл. Таким образом, объект данных уже может проверить правильность ограничений между параметрами.
Для всех моих проектов в прошлом, когда я пришел к выводу, что у меня слишком много параметров (и это было 8 не 28!), я смог дезинформировать код, создав лучшую datamodel.
Ответ 5
Поскольку вы ограничены Java 1.4, если вы хотите DI, то Spring будет очень приличным вариантом. DI полезно только в тех местах, где параметры конструктора - это службы или что-то, что не меняется во время выполнения.
Если у вас есть все эти разные конструкторы из-за того, что вам нужны переменные параметры построения объекта, вам следует серьезно подумать об использовании шаблона Builder.
Ответ 6
Лучшее решение - не слишком много параметров в конструкторе. Только параметры, действительно необходимые в конструкторе, являются параметрами, которые необходимо правильно инициализировать объект. Вы можете иметь конструкторы с несколькими параметрами, но также иметь конструктор с минимальными параметрами. Дополнительные конструкторы называют этот простой конструктор и после этого устанавливают другие параметры. Таким образом, вы можете избежать проблемы цепочки с большим количеством параметров, но также иметь некоторые конструкторы удобства.
Ответ 7
Я действительно рекомендую использовать Immutables или POJOBuilder при использовании шаблона построителя.
Ответ 8
Рефакторинг для уменьшения количества параметров и глубины вашей иерархии наследования - это почти все, о чем я могу думать, потому что ничто действительно не поможет сохранить 20-то параметры прямо. Вы просто будете иметь к каждому звонку, глядя на документацию.
Одна вещь, которую вы могли бы сделать, - сгруппировать некоторые логически сгруппированные параметры в свой собственный объект более высокого уровня, но у этого есть свои проблемы.