Вызывающие сеттеры от конструктора - программирование
Подтвердить что ты не робот

Вызывающие сеттеры от конструктора

Что такое pro и con для вызова мутатору из конструктора (если есть)

то есть:.

public MyConstructor(int x) {
  this.x = x;
}

против

public MyConstructor(int x) {
  setX(x);
}

public void setX(int x) {
  this.x = x;
}

Есть ли у вас предпочтения? (Это не домашнее задание, просто глядя на наш стандарт стандартов кодирования, где он говорит, чтобы всегда вызывать мутаторы при установке экземпляра var в конструкторе, и я не всегда к этому)

4b9b3361

Ответ 1

Лично я бы установил переменную непосредственно в большинстве случаев.

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

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

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

Ответ 2

Я следую двум правилам о конструкторах, чтобы свести к минимуму проблемы, поэтому я не буду использовать метод mutator:

Конструкторы (не конечных классов) должны вызывать только конечные или частные методы. Если вы решите игнорировать это правило и позволить конструктору вызывать нефинал/не-частные методы, то:

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

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

[[@Jon Skeet упоминает это в своем ответе: "... В частности, вызов переопределенного метода от конструктора - это рецепт для трудно понятного кода и труднодоступных ошибок". Но я не думаю, что последствия этой проблемы достаточно подчеркнуты. ]]

Конструкторы должны быть осторожны при утечке this до того, как экземпляр будет полностью инициализирован. Пока предыдущее правило касалось методов внутри класса и подклассов, обращающихся к ivars, вы также должны быть осторожны (даже окончательный /private ), передавая this другим классам и служебным функциям до this полностью инициализируется. Чем больше не закрытых, переопределяемых методов, вызываемых конструктором, тем выше риск утечки this.


Некоторые ссылки на конструкторы, вызывающие нефинансовые, не частные методы:

https://www.securecoding.cert.org/confluence/display/java/MET05-J.+Ensure+that+constructors+do+not+call+overridable+methods

http://www.javaworld.com/article/2074669/core-java/java-netbeans--overridable-method-call-in-constructor.html

http://www.javaspecialists.eu/archive/Issue210.html

Ответ 3

Я редко это делаю, и из-за этого у меня никогда не было проблемы. Он также может иметь непреднамеренные последствия, особенно если ваши сеттеры переопределены в подклассе или если ваши сеттеры отменяют дополнительные вызовы методов, которые могут быть неприменимы во время инициализации.

Ответ 4

Это зависит от того, как вы относитесь к сеттерам. Если вы считаете, что класс может быть получен, вы можете разрешить такой вызов, чтобы вы могли переопределить поведение в другом месте. В противном случае вы можете установить его как это.

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

Ответ 5

Если ваш сеттер делает что-то более сложное, чем this.x = x, я просто установил бы переменную напрямую. Параметр отображается непосредственно в вашу переменную экземпляра, и для меня это более увлекательно.

Ответ 6

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

Это огромная экономия времени в кодовой базе, которая достигла 2 миллионов строк кода, а также облегчает рефакторинг.

Ответ 7

Я тоже не возражаю, и у меня нет сильных префов [и не придерживайтесь каких-то строгих стандартов], просто используйте свое мнение. Но если вы идете с сеттерами, любой, кто переопределяет класс, должен знать, что объект не может быть полностью создан. При этом убедитесь, что дополнительный код в сеттерах не может опубликовать ссылку this.

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

Использование поля имеет очевидные преимущества (например, если кто-либо из подклассов не сможет злонамеренно изменить поведение), и обычно это предпочтительнее, особенно. в библиотеках.

Фактически, c-tor является одним из 3 возможных способов создания объекта (сериализация + клон - это другие 2), может потребоваться некоторое переходное состояние вне c-tor, так что вам все равно нужно подумать о полях против сеттеров. (Изменить, есть еще одна половина: Небезопасно, но то, что использует сериализация)

Ответ 8

Мое предпочтение заключается в том, чтобы установить их непосредственно в конструкторе по нескольким причинам. Во-первых, что-то вроде this.x = x; так же ясно, если не больше, чем вызов отдельного метода, который делает то же самое. Во-вторых, метод может быть потенциально переопределен, если он не будет помечен как окончательный, а вызов потенциально переопределенных методов из конструктора - это большое значение no-no в моей книге. В-третьих, большинство методов обычно предполагают, что объект уже завершен, когда они выполняются, а не на полпути к его построению. Хотя это не должно вызывать каких-либо проблем в этом простом случае, в более сложных случаях это может вызвать серьезные тонкие ошибки, требующие возраста для отслеживания.

Основным аргументом в пользу использования сеттеров/геттеров во всем мире является то, что это означает, что вы можете переименовать поле, просто изменив его имя в 3-х местах, его определение, методы getter/setter, и все должно компилироваться и быть в порядке. На мой взгляд, этот аргумент недействителен в наши дни, поскольку любая достойная современная среда IDE переименует все вхождения такого поля с помощью простого сочетания клавиш.

Ответ 9

Вызов любых методов public, static, non-final в конструкторе, которые вам подходят, но наилучшая практика никогда не вызывает такие методы внутри конструктора, потому что эти методы могут быть переопределены в подклассах и на самом деле только переопределенная версия эти методы будут вызываться (если вы используете полиморфное поведение).

Например:

public class Foo {

public Foo() {
    doSmth(); // If you use polymorphic behavior this method will never be invoked
}

public void doSmth() {
    System.out.println("doSmth in super class");
}

public static void main(String[] args) {
    new Bar(200);
}
}

class Bar extends Foo {

private int y;;

public Bar(int y) {
    this.y = y;
}

@Override
public void doSmth() { // This version will be invoked even before Barr object initialized
    System.out.println(y);
}

}

Он выведет 0.

Для более подробной информации читайте Брюс Экель "Мышление в Java" глава "Полиморфизм"