Часто я обнаруживаю, что я должен создать экземпляр кучки объектов, но мне легче предоставить параметры для этого экземпляра в виде текстового файла с возможностью чтения человеком, который я вручную компоную и загружаю в программу в качестве входных данных.
Например, если объект является Car
, тогда файл может представлять собой группу строк, каждая из которых содержит имя, скорость и цвет (три обязательных параметра конструктора), разделенные вкладками:
My car 65 Red
Arthur car 132 Pink
Old junk car 23 Rust brown
Это легко проверить визуально, изменить или сгенерировать другую программу. Затем программа может загрузить файл, взять каждую строку, проанализировать соответствующие параметры, передать их в конструктор Car(string name, int speed, uint color)
и создать объект.
Обратите внимание на то, что на входе должна выполняться некоторая работа, прежде чем она будет совместима с конструктором. Скорость должна быть преобразована из string
в int
с вызовом int.Parse
. Цвет должен соответствовать значению RGB, просматривая английское имя цвета (возможно, программа будет получать доступ к Википедии, чтобы выяснить каждое значение цвета, или где-нибудь проконсультируется с предопределенной картой имени → RGB).
Мой вопрос: с точки зрения ООП, кто должен делать этот разбор? Конструктор или метод, вызывающий конструктор?
При первом варианте преимущество - простота. Вызывающая функция должна выполнять только:
foreach(var row in input_file)
list_of_objects_that_i_am_populating.Add(new Car(row));
И все уродливые синтаксические разборки могут содержаться в конструкторе, у которого нет никакого другого кода, так что код синтаксического анализа может быть легко прочитан и изменен, не отвлекаясь на несовместимый код.
Недостатком является то, что повторное использование кода выходит из окна, потому что теперь мой объект присоединяется к бедеру к входному формату (хуже того, поскольку формат ввода является ad-hoc и составлен вручную, он является эфемерным и потенциально не гарантируется тоже самое). Если я повторно использую этот объект в другой программе, где я решаю, что удобно слегка изменить форматирование входного файла, две версии определения объекта теперь расходятся. Я часто обнаруживаю, что определяю форматы ввода в разделе комментариев конструктора, который кажется немного вонючим.
Другим недостатком является то, что я потерял способность выполнять пакетные операции. Вспомните предыдущую примерную проблему сопоставления имен цветов со значениями. Что делать, если я использую веб-службу, которая занимает 1 минуту для обработки каждого отдельного запроса, независимо от того, просит ли этот запрос преобразовать одно имя цвета или миллион. С очень большим входным файлом я резко сократил бы свое приложение, обратившись к службе один раз для каждой строки, вместо того, чтобы отправлять один большой запрос для всех строк, а затем создавать экземпляры объектов в соответствии с ответом.
Каков "правильный" способ справиться с такой ситуацией? Должен ли я разбирать ввод конструктора и рассматривать вышеперечисленные проблемы как исключительные проблемы, которые необходимо решать в каждом конкретном случае? Должен ли я позволить моему методу вызова выполнять разбор (хотя он может уже раздуваться с помощью много запутанной программной логики)?