Подтвердить что ты не робот

Любая проблема с выполнением основной работы класса в его конструкторе?

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

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

Один пример: мне нужно получить некоторую информацию, относящуюся к СУБД, из базы данных. Самый естественный способ для меня, казалось, имел класс DBMSSpecInfo, с конструктором:

public DBMSSpecInfo(java.sql.Connection conn) throws SQLException{
  // ... retrieve info from DBMS
}

/** @returns max size of table in kiB */
public int getMaxTableSize() {//...}

/** @returns max size of index in kiB */
public int getMaxIndexSize() {//...}

/** @returns name of default schema */
public String getDefaultSchema() {//...}

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

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

И что ты думаешь? Существуют ли проблемы с выполнением основной работы в конструкторе? Является ли это "неидиоматическим" в Java? Или это приемлемая (хотя, возможно, необычная) практика?

4b9b3361

Ответ 1

В вашем примере я бы сделал статический метод GetDBMSSpecInfo (java.sql.Connection conn), который вернет экземпляр объекта DBMSSpecInfo или null, если что-то пойдет не так ( в случае, если вы не хотите бросать исключения).

Объект DBMSSpecInfo для меня не должен содержать ничего, кроме свойств: MaxIndexSize, MaxTableSize, DefaultSchema и т.д.

И я бы сделал конструктор этого объекта закрытым, чтобы экземпляры могли быть созданы только из статического метода.

Ответ 2

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

Связанный разговор: OO Design для проверки. В нем приводятся примеры того, почему работа над конструкторами плохо для модульного тестирования.

Ответ 3

Я бы предпочел отделить код создания от самого класса в таких случаях. Его можно поместить в статический метод factory или отдельный класс factory (который также может быть общедоступным статическим внутренним классом). Выбор зависит от сложности кода и контекста дизайна (чего мы не знаем в этом случае).

Это также позволит вам делать оптимизации, такие как кеширование и повторное использование экземпляров класса.

Ответ 4

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

Этот класс путает содержимое данных с механизмом его извлечения. Объект, который вы в конечном итоге используете в другом месте, интересен только для содержащихся в нем данных. Таким образом, "чистая" вещь должна состоять в том, чтобы иметь другой класс для выкапывания информации, а затем для создания экземпляров этого объекта свойств.

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

Ответ 5

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

Ответ 6

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

Другим является то, что конструктор все или ничего. Если объект содержит данные, чьи инициализации демонстрируют независимые сбои, вы лишаете себя возможности использовать то, какие данные могут быть успешно приобретены. Точно так же вы должны инициализировать весь объект, даже если вам просто нужна его часть, может отрицательно повлиять на производительность.

С другой стороны, выполнение этого в конструкторе позволяет использовать состояние инициализации (здесь: соединение с базой данных) и выпускаться ранее.

Как всегда, разные подходы предпочтительны в разных обстоятельствах.

Ответ 7

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

Ответ 8

Просто будьте осторожны, чтобы объект не был клонирован/десериализован. Экземпляры, созданные таким образом, не используют конструктор.

Ответ 9

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

Ответ 10

Нет проблем. JDK имеет много классов, которые выполняют сетевые функции ввода-вывода в конструкторах.