Перегрузка конструктора в 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,

Конструкторы

Объяснение конструктора.