Перегрузка конструктора в Java - лучшая практика
Есть несколько тем, похожих на это, но я не мог найти один с достаточным ответом.
Я хотел бы знать, что лучше всего подходит для перегрузки конструктора в Java. У меня уже есть свои мысли по этому вопросу, но я хотел бы услышать больше советов.
Я имею в виду перегрузку конструктора в простой перегрузке класса и конструктора при наследовании уже перегруженного класса (что означает, что базовый класс имеет перегруженные конструкторы).
Спасибо:)
Ответы
Ответ 1
Пока нет "официальных рекомендаций", я придерживаюсь принципа KISS и DRY. Сделайте перегруженные конструкторы настолько простыми, насколько это возможно, и самый простой способ заключается в том, что они только называют это (...). Таким образом вам нужно всего лишь один раз проверить и обработать параметры.
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
}
}
С точки зрения модульного тестирования станет легче тестировать класс, поскольку вы можете вложить в него ресурсы. Если у класса много ресурсов (или соавторов, как его называют некоторые OO-geeks), рассмотрите одну из этих двух вещей:
Сделать класс параметров
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 просто либо должен разбить параметр 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;
}
Сделайте класс factory
Создайте класс factory, который инициализирует ресурсы для вас, что выгодно, если инициализация ресурсов немного сложна:
public interface ResourceFactory {
public Resource createR1();
public Resource createR2();
}
Затем конструктор выполняется так же, как и с классом параметров:
public Simple(ResourceFactory factory) {
this(factory.createR1(), factory.createR2());
}
Сделайте комбинацию обоих
Да... вы можете смешивать и сопоставлять оба пути в зависимости от того, что вам легче в то время. Классы параметров и простые классы factory в значительной степени совпадают с классом Simple
, что они используются одинаково.
Ответ 2
Я думаю, что лучше всего иметь единственный первичный конструктор, к которому относятся перегруженные конструкторы, вызывая this()
с соответствующими параметрами по умолчанию. Причиной этого является то, что он делает намного понятнее, что такое построенное состояние объекта, - действительно, вы можете думать о том, что основной конструктор является единственным реальным конструктором, другие просто делегируют ему
Одним из примеров этого может быть JTable
- первичный конструктор принимает TableModel
(плюс столбец и модели выбора), а другие конструкторы называют этот первичный конструктор.
Для подклассов, в которых суперкласс уже имеет перегруженные конструкторы, я хотел бы предположить, что разумно рассматривать любой из конструкторов родительского класса как первичный и полагать, что совершенно законно не иметь ни одного первичного конструктора. Например, при расширении Exception
я часто предоставляю 3 конструктора, один из которых принимает только сообщение String
, один из которых принимает причину Throwable
, а другой принимает оба. Каждый из этих конструкторов напрямую вызывает super
.
Ответ 3
Если у вас очень сложный класс с множеством опций, для которых допустимы только некоторые комбинации, подумайте об использовании Builder. Очень хорошо работает как по коду, так и по логике.
Builder - это вложенный класс с методами, предназначенными только для установки полей, а затем конструктор ComplexClass принимает такой Builder как аргумент.
Изменить: конструктор ComplexClass может гарантировать правильность состояния в Builder. Это очень сложно сделать, если вы просто используете сеттеры на ComplexClass.
Ответ 4
Это действительно зависит от типа классов, поскольку не все классы созданы равными.
В качестве общего руководства я бы предложил два варианта:
- Для классов и неизменяемых (Exception, Integer, DTO и т.д.) используйте единственный первичный конструктор, как это предложено в приведенном выше ответе
- Для всего остального (сеанс beans, сервисы, изменяемые объекты, сущности JPA и JAXB и т.д.) используйте конструктор по умолчанию только с разумными значениями по умолчанию для всех свойств, поэтому его можно использовать без дополнительных конфигурация
Ответ 5
Ну, вот пример для перегруженных конструкторов.
public class Employee
{
private String name;
private int age;
public Employee()
{
System.out.println("We are inside Employee() constructor");
}
public Employee(String name)
{
System.out.println("We are inside Employee(String name) constructor");
this.name = name;
}
public Employee(String name, int age)
{
System.out.println("We are inside Employee(String name, int age) constructor");
this.name = name;
this.age = age;
}
public Employee(int age)
{
System.out.println("We are inside Employee(int age) constructor");
this.age = age;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
}
В приведенном выше примере вы можете увидеть перегруженные конструкторы. Имя конструкторов одинаковое, но каждый из них имеет разные параметры.
Вот некоторые ресурсы, которые проливают больше света на перегрузку конструктора в Java,
Конструкторы
Объяснение конструктора.