Вопрос:
Скажем, мы используем Java SE (без библиотек) и имеем следующую ситуацию. У нас есть класс:
public class DriverInfo { private final int age; public DriverInfo(int age) { this.age = age; } // getter here }
В некоторых странах есть требование, чтобы вы могли ездить, если вам исполнилось 18 лет. Другими словами – нам нужно иметь некоторую проверку для параметра возраста. Что-то вроде:
if (age < 18) { throw new IllegalArgumentException(«Age is not valid!»); }
Итак, мой вопрос: где эта проверка должна быть? Мои мысли таковы:
- В конструкторе добавьте if(), описанное выше. Проверка будет работать, если конструктор вызывается из нескольких мест вашего кода. Меня беспокоит, что конструкторы классов должны (ИМХО) не содержать никакой логики. Я прав?
- Проверяйте где-то вне конструктора – будь то фабричный метод, класс строителя и т.д. Но тогда мы заставляем разработчиков не создавать экземпляр класса с помощью конструктора, а использовать какой-либо искусственный завод/строитель.
- Чтобы проверить параметры конструкторов с помощью Validate. Это не стандартная Java, но я видел, как люди это делали. Что касается меня, это выглядит не так, потому что мы добавляем логику к конструктору – что не подходит для меня.
- Любой другой хороший способ, который я пропустил?
Любые мысли будут высоко оценены. Кто-нибудь может предложить лучшую практику, как справиться с описанной ситуацией обитания?
Лучший ответ:
Проверка в конструкторе полностью в порядке. Это правило “без логики в конструкторе” к нему не относится, но, к сожалению, оно немного сформулировано. Задача конструктора – извлекать зависимости извне (внедрение зависимостей), проверять их действительность и затем, вероятно, сохранять их в атрибутах экземпляра – создавая действительный экземпляр, короче говоря
Таким образом, правила того, что является действительным, а что нет, хранятся внутри объекта, а не на некотором заводе.
Если экземпляр будет недействительным, то генерировать исключение, которое объясняет, что не так с параметрами, абсолютно нормально. Это предотвращает перемещение недействительных экземпляров по системе.
Кроме того, с неизменяемыми объектами вы гарантируете, что все существующие экземпляры действительны все время, и это здорово.
Наличие некоторого метода валидации объекта возможно и может быть полезно, но я бы предпочел валидацию конструктора в любой день. Но если это невозможно, то это лучше, чем ничего, и оно все еще сохраняет правила для валидности внутри объекта. Например, когда какой-то фреймворк создает ваш изменчивый объект для вас и требует конструктора без параметров… вы можете забыть вызвать его, но это лучше, чем ничего.
Ответ №1
Я думаю, есть еще два метода, которые вы можете использовать.
-
Передавайте переменные super() и проверяйте их в родительском классе. Например
супер (возраст)
-
Вы можете использовать геттеры, сеттеры и проверять переменную там. Я пробовал использовать сеттеры в java.
public class validate_object_variable { private int age; public int getAge() { return age; } public void setAge(int age) { if(this.age >= 18) this.age = age; else { throw new IllegalArgumentException(«Age is not valid!»); } } public static void main(String args[]) { validate_object_variable obj = new validate_object_variable(); obj.setAge(10); System.out.println(obj.getAge()); } }
Это дает мне возможность чисто выходить с допустимым исключением для вызывающего.
ВЫВОД
Я думаю, было бы неплохо бросить исключения в конструкторе. Но это хороший выбор для проверки переменных с помощью селекторов отдельно, не мешая созданию объекта.
Ответ №2
На мой взгляд, у вас должен быть метод внутри класса DriverInfo, что-то вроде:
public boolean isDriverLegalAge(int age){ if (age < 18) { return false; } else { return true; } }
Конструктор должен использоваться только для создания объекта. Все, что связано с логикой внутри этого объекта, должно быть внутри методов.
Для получения дополнительной информации о назначении конструктора см. Эту ссылку: qaru.site/questions/379684/…
Ответ №3
Я думаю, вы также можете использовать шаблон Builder для таких случаев использования. Хотя проверка конструктора совершенно прекрасна, и обычно Builder имеет тенденцию вводить много кода Boiler Plate, но если вы хотите избежать проверки внутри конструктора, а также хотите иметь неизменный класс (без проверки сеттера), вы можете дать разработчикам попробовать.
Обычно строители должны использоваться, когда сталкиваются со многими параметрами конструктора. Вы можете прочитать больше строителей здесь.
public class DriverInfo { private final int age; //more parameters here private DriverInfo(int age) { this.age = age; } public int getAge() { return age; } public static DriverInfoBuilder newBuilder() { return new DriverInfoBuilder(); } public static final class DriverInfoBuilder { private int age; private DriverInfoBuilder() { } public DriverInfoBuilder age(int age) { this.age = age; return this; } public DriverInfo build() { if (age < 18) { throw new IllegalArgumentException(«Age is not valid!»); } //other validations. return new DriverInfo(age); } } }
Опять же есть много способов сделать это, и здесь нет правильного и неправильного. Его больше о том, что он предпочитает, и будет ли он доступен для других программистов или нет.