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

Делает много в конструкторах плохо?

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

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

С другой стороны, это немного странно. Более того, в этот разговор примерно в 17:58 есть веские причины не делать много работы в конструкторе. Я думаю, что я могу устранить проблему, передав соответствующие манекены в качестве аргументов конструктора.

Остается вопрос: много ли работает (или даже вся работа) в конструкторах?

4b9b3361

Ответ 1

Я думаю, что "Выполнение работы в конструкторе" в порядке...

... пока вы не нарушаете Принцип единой ответственности (SRP) и придерживаться Injection Dependency (DI).

Я задавал себе этот вопрос слишком поздно. И мотивация против выполнения работы в конструкторе, который я нашел, либо:

  • Трудно проверить
    • Все примеры, которые я видел, были где DI не использовалась. На самом деле не виноват конструктор, выполняющий фактическую работу.
  • Возможно, вам не нужны все результаты, которые вычисляет ваш конструктор, теряя время обработки, и сложно тестировать изолированно.
    • Это в основном нарушение SRP, а не ошибка конструктора, выполняющего работу за ответ.
  • У старых компиляторов есть/были проблемы с исключениями, брошенными в конструкторы, поэтому вы не должны делать ничего, кроме назначения полей в конструкторах.
    • Я не думаю, что это хорошая идея, чтобы написать новый код, учитывающий недостатки статистического компилятора. Мы могли бы также покончить с С++ 11 и все, что хорошо вместе, если мы это сделаем.

Мое мнение таково, что...

... если ваш конструктор должен работать, чтобы он придерживался Инициализация ресурсов (RAII) ), и класс не нарушает SRP и DI правильно используется; Тогда выполнение работы в конструкторе A-Okay! Вы даже можете исключить исключение, если хотите предотвратить использование объекта класса, инициализация которого завершилась неудачно, вместо того, чтобы полагаться на пользователя, чтобы проверить возвращаемое значение.

Ответ 2

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

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

С учетом сказанного вы заметите, что он также затрагивает зависимость внедрения/шаблон поставщика, который печально известен сложными конструкторами. В этом случае предпочтительнее оставлять ТОЛЬКО код провайдера /DI в конструкторе. Опять же, ответ зависит от того, какие шаблоны вы используете и как ваш код "подходит" вместе.

Вся цель использования конструктора - для создания аккуратного объекта, который может быть использован немедленно; т.е. new Student("David Titarenco", "Senior", 3.5). Нет необходимости делать david.initialize(), поскольку это было бы совершенно глупо.

Вот некоторые из моего производственного кода, например:

    Config Conf = new Config();
    Log.info("Loading server.conf");
    Conf.doConfig();

В приведенном выше случае я решил ничего не делать с конструктором (он пуст), но имеет метод doConfig(), который выполняет весь диск i/o; Я часто думал, что метод doConfig() просто бессмыслен, и я должен делать все в конструкторе. (Я только проверю файл конфигурации один раз, в конце концов.)

Я думаю, что он полностью зависит от вашего кода, и вы не должны думать, что положить "материал" в ваш конструктор - это плохо. Для чего нужны конструкторы! Иногда мы увлекаемся ООП (getThis, setThat, doBark), когда действительно весь класс должен делать, это загрузить файл конфигурации. В таких случаях просто поместите все в конструктор и назовите его днем!

Ответ 3

Обычно, если ваш объект имеет сложный алгоритм создания, вы, вероятно, могли бы упростить его с помощью Builder или Factory. Специально, если существуют предварительные условия для проверки для создания объекта.

Как только вы начнете использовать Builders and Factories для создания своих объектов, они смогут проверить условия pre и post и убедиться, что клиенты вашего кода смогут получить доступ к полностью инициализированному объекту, а не к полуделам one, вы даже можете использовать современные в моде плавные интерфейсы для создания своего объекта и сделать его крутым, D

new EmailMessage()
    .from("[email protected]")
    .to("[email protected]")
    .withSubject("Fluent Mail API")
    .withBody("Demo message")
    .send();

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

Ответ 4

У меня возникли следующие проблемы, когда я добавлял слишком много кода в конструктор:

  • Было сложно написать модульные тесты для других методов этого класса, потому что он хотел сделать много вещей в конструкторе, таким образом, я должен был установить множество действительных вещей или, по крайней мере, mocks (DB, file, что угодно) для простейших модульных тестов.
  • Трудно было написать модульные тесты для самого конструктора. Так или иначе, ставя много кода с разнообразными обязанностями в один блок - даже плохая идея. (Простой принцип ответственности.)
  • По прежним причинам было трудно использовать этот класс. Например, это полностью помешало мне реализовать некоторые отложенные методы init, потому что ему нужно все в момент вызова конструктор. Хорошо, я мог бы написать ленивый метод init в конструктор, хороший.
  • Рано или поздно я понял, что имеет смысл повторно использовать некоторые части кода которые помещаются в конструктор. Хорошо, когда я впервые написал конструктор Я также думал, что эти части кода будут использоваться только там, навсегда.
  • Когда я хотел расширить этот класс и вставить некоторую логику до или в логику супер-конструктора это просто не сработало, потому что первое, что нужно сделать в конструкторе расширенного класса, - это вызвать супер один.

Так что да, делать много в конструкторе - плохая идея, на мой взгляд.

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

Ответ 5

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

Пример: Допустим, у вас есть класс, который читает файл, анализирует его и сообщает вам информацию, как сумму всех чисел в файле. Вы можете сделать это все в конструкторе. Используя ленивую оценку, вы просто откроете файл и получите функцию getTotalSum(). Когда он будет вызван, он выполнит разбор и даст вам результат. Таким образом, вы можете также получить getBestFit(), чтобы получить наилучшую линию соответствия. Иногда вы не хотите, чтобы все было в порядке, и для некоторых материалов, которые вы делаете. Таким образом, пользователь не будет ждать, пока конструктор выполнит вычисления до того, как пользователь решит, что делать.

другой пример: скажем, у вас есть представление, которое загружает 20 изображений. Но показано только 5, а конструктор отображает массив изображений. Вы можете загрузить их все в конструкторе, но с точки зрения пользователей это будет очень медленным с самого начала. Или вы можете загрузить 1 "загрузку" изображения и загрузить 1 изображение за раз. А поскольку пользователь прокручивает, загружает больше изображений в соответствии с показанной/необходимой базой.

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