Любая проблема с выполнением основной работы класса в его конструкторе? - PullRequest
12 голосов
/ 29 сентября 2010

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

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

Один пример: мне нужно извлечь некоторую информацию, относящуюся к СУБД, из базы данных. Мне показалось, что наиболее естественным способом является класс 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? Или это приемлемая (хотя, возможно, необычная) практика?

Ответы [ 10 ]

10 голосов
/ 29 сентября 2010

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

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

6 голосов
/ 29 сентября 2010

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

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

5 голосов
/ 29 сентября 2010

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

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

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

4 голосов
/ 29 сентября 2010

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

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

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

3 голосов
/ 29 сентября 2010

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

2 голосов
/ 29 сентября 2010

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

2 голосов
/ 29 сентября 2010

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

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

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

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

1 голос
/ 30 сентября 2010

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

0 голосов
/ 29 сентября 2010

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

0 голосов
/ 29 сентября 2010

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

...