Вопрос-ответ

Constructor overloading in Java - best practice

Перегрузка конструктора в Java - лучшая практика

Есть несколько тем, похожих на эту, но я не смог найти ни одной с достаточным ответом.

Я хотел бы знать, какова наилучшая практика перегрузки конструктора в Java. У меня уже есть свои мысли по этому поводу, но я хотел бы услышать больше советов.

Я имею в виду как перегрузку конструктора в простом классе, так и перегрузку конструктора при наследовании уже перегруженного класса (имеется в виду, что базовый класс имеет перегруженные конструкторы).

Спасибо :)

Переведено автоматически
Ответ 1

Пока нет "официальных рекомендаций", я следую принципу "ПОЦЕЛОВАТЬ и ВЫСУШИТЬ". Сделайте перегруженные конструкторы как можно более простыми, и самый простой способ заключается в том, чтобы они вызывали только this(...) . Таким образом, вам нужно будет проверять и обрабатывать параметры только один раз.

public class Simple {

public Simple() {
this(null);
}

public Simple(Resource r) {
this(r, null);
}

public Simple(Resource r1, Resource r2) {
// Guard statements, initialize resources or throw exceptions if
// the resources are wrong
if (r1 == null) {
r1 = new Resource();
}
if (r2 == null) {
r2 = new Resource();
}

// do whatever with resources
}

}

С точки зрения модульного тестирования протестировать класс станет проще, поскольку вы сможете вложить в него ресурсы. Если в классе много ресурсов (или соавторов, как называют это некоторые ОО-гики), рассмотрите одну из этих двух вещей:

Создайте класс параметров

public class SimpleParams {
Resource r1;
Resource r2;
// Imagine there are setters and getters here but I'm too lazy
// to write it out. you can make it the parameter class
// "immutable" if you don't have setters and only set the
// resources through the SimpleParams constructor
}

Конструктору в Simple only либо нужно разделить SimpleParams параметр:

public Simple(SimpleParams params) {
this(params.getR1(), params.getR2());
}

... или создайте SimpleParams атрибут:

public Simple(Resource r1, Resource r2) {
this(new SimpleParams(r1, r2));
}

public Simple(SimpleParams params) {
this.params = params;
}

Создайте заводской класс

Создайте заводской класс, который инициализирует ресурсы для вас, что удобно, если инициализация ресурсов немного затруднена:

public interface ResourceFactory {
public Resource createR1();
public Resource createR2();
}

Затем конструктор выполняется тем же способом, что и с классом параметров:

public Simple(ResourceFactory factory) {
this(factory.createR1(), factory.createR2());
}

Создайте комбинацию обоих

Да ... вы можете комбинировать оба способа в зависимости от того, что вам проще в данный момент. Классы параметров и простые заводские классы - это практически одно и то же, учитывая, что Simple класс использует их одинаково.

Ответ 2

Я думаю, что наилучшей практикой является наличие одного основного конструктора, на который перегруженные конструкторы ссылаются при вызове this() с соответствующими параметрами по умолчанию. Причина этого в том, что это намного проясняет, что такое сконструированное состояние объекта - на самом деле вы можете думать о первичном конструкторе как о единственном реальном конструкторе, остальные просто делегируют ему

Одним из примеров этого может быть JTable - основной конструктор принимает TableModel (плюс модели столбцов и выбора), а другие конструкторы вызывают этот основной конструктор.

Для подклассов, где в суперклассе уже есть перегруженные конструкторы, я бы склонен предположить, что разумно рассматривать любой из конструкторов родительского класса как основной, и думаю, что совершенно законно не иметь ни одного основного конструктора. Например, при расширении Exception я часто предоставляю 3 конструктора, один из которых принимает только String сообщение, другой принимает Throwable причину, а другой принимает оба. Каждый из этих конструкторов вызывает super напрямую.

Ответ 3

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

Конструктор - это вложенный класс с методами, предназначенными только для задания полей, и тогда конструктор ComplexClass принимает такой конструктор только в качестве аргумента.


Редактировать: конструктор ComplexClass может гарантировать, что состояние в конструкторе является допустимым. Это очень сложно сделать, если вы просто используете установщики в ComplexClass.

Ответ 4

Это действительно зависит от типа классов, поскольку не все классы созданы равными.

В качестве общего руководства я бы предложил 2 варианта:


  • Для классов значений и неизменяемых (Exception, Integer, DTO и подобных) Используйте единый первичный конструктор, как предложено в приведенном выше ответе

  • Для всего остального (сеансовые компоненты, сервисы, изменяемые объекты, сущности JPA и JAXB и так далее) Используйте только конструктор по умолчанию с разумными значениями по умолчанию для всех свойств, чтобы его можно было использовать без дополнительной настройки

java