2008-10-21 3 views
82

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

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

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

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

ответ

219

Паттерн Builder Design может помочь. Рассмотрим следующий пример

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 сгенерирует исключение. И это позволяет нам иметь аргументы по умолчанию/необязательные, не требуя отслеживания какого-либо порядка аргументов, так как любой порядок этих вызовов будет работать одинаково хорошо.

+8

Конечно, со статическим импортом вам даже не придется «видеть» этих «строителей» вообще. Например, у вас может быть имя статических методов (String name), которое возвращает строитель и Student (StudentBuilder), который возвращает ученика. Следовательно, Студент (имя («Джо»). Возраст (15). Мотто («Я промочил себя»)); – 2008-10-21 20:46:34

1

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

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

3

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

4

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

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

+0

Параметры - это в основном услуги, как вы упомянули, и поэтому DI - это то, что мне нужно. Я думаю, что шаблон Builder, упомянутый в нескольких других ответах, - именно то, на что я надеялся. – 2008-10-21 20:08:43

14

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

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

См стр 8 и последующих this Josh Bloch presentation (PDF), или this review of Effective Java

21

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

например, если параметры как

 

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; 
} 
 
5

Ну, используя шаблон строитель может быть один решение.

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

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

2

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