Вопрос по java, constructor, constructor-overloading, overloading – Перегрузка конструктора в Java - лучшая практика

100

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

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

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

Спасибо :)

Ваш Ответ

5   ответов
0

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,

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

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

159

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

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-гики), рассмотрим одну из следующих двух вещей:

Make a parameter class
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());
}

& # x2026; или сделатьSimpleParams атрибут:

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

public Simple(SimpleParams params) {
    this.params = params;
}
Make a factory class

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

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

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

public Simple(ResourceFactory factory) {
    this(factory.createR1(), factory.createR2());
} 
Make a combination of both

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

+1 очень хороший пост
Можно ли иметь несколько конструкторов с 1 параметром разного типа на каждом? Как - новый объект (int aa) / новый объект (строка bb)?
@ JosieThompson Насколько я знаю, это не определено ни в одном стандарте. Я согласен, что наличие полного конструктора в первую очередь полезно для быстрого просмотра всех параметров метода; упорядочение их по количеству аргументов, однако, позволяет вам следить за перегруженными вызовами вниз по странице, что может быть более естественным, если учесть, как мы читаем и пишем код.
Я заметил в этом, а также в других примерах, что определения конструктора записаны в порядке, который использует наименьшее количество аргументов в вызове конструктора. Это стандартный стиль Java? Почему ?: По моему мнению, было бы целесообразно сделать это противоположным образом, чтобы вы увидели первое определение конструктора, которое содержит все детали.
6

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

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

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

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

single primary constructor на которые ссылаются перегруженные конструкторы, вызываяthis() с соответствующими параметрами по умолчанию. Причина этого заключается в том, что это делает более понятным, что являетсяconstructed state объекта - на самом деле вы можете думать о первичном конструкторе какonly real constructorостальные просто делегируют ему

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

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

Я думаю, что это излишне ограничительно.
Я изменил свой ответ из этого пояснения
Я думаю "уже перегруженные классы" означало, что базовый класс имеет несколько перегруженных конструкторов.
Я согласен с первой частью, но не со второй частью наследования уже перегруженного класса: скажем, я наследую исключение для нового класса, где я хочу, чтобы строка исключения начиналась с «bla». - это означает, что я должен проверить это в конструкторах, получающих String. В случае, если я не вызываю первичный конструктор, как в базовом классе, я должен повторить код этой проверки. Eyal Roth
Да, это то, что я имел в виду. Eyal Roth
2

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

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

For value & immutable classes (Exception, Integer, DTOs and such) use single primary constructor as suggested in above answer For everything else (session beans, services, mutable objects, JPA & JAXB entities and so on) use default constructor only with sensible defaults on all the properties so it can be used without additional configuration

Похожие вопросы