Страницы

Поиск по вопросам

четверг, 1 ноября 2018 г.

Как правильно проектировать классы с большим количеством обязательных параметров?

Мне требуется создать достаточно массивный класс, координирующий работу ряда объектов. Для его работы необходимо отправить ему около пятнадцати объектов. Без них его работа не возможна, по этому было принято решение отправлять все объекты через конструктор. Естественно, что конструктор на 10+ аргументов выглядит просто ужасно! Есть альтернатива отправлять все объекты посредством свойств, но этот способ имеет свои недостатки. Придётся лепить дополнительные проверки на null и выкидывать исключения. Да и стороннему разработчику, если потребуется работать с таким классом придётся потратить дополнительный усилия, что бы не пропустить никакого важного свойства.
Как быть? Множество аргументов в конструкторе? Или множество свойств обязательных к заполнению?


Ответ

Есть такой анти-паттерн God он же Божественный объект. Его главная особенность — он может всё. Такой объект нарушает принцип единственной ответственности, и, скорее всего, его можно разбить на три или четыре несвязанных класса.
Если посмотреть на ту же ситуацию под другим углом зрения, можно говорить о ней, как об ошибке декомпозиции: перескакивании на несколько уровней вниз. Например, вещество состоит из молекул, молекулы из атомов, атомы из протонов, нейтронов и электронов, протоны и электроны — из кварков. Естественно, можно сказать, что молекулы состоят из протонов и электронов, и это правда, но, пропустив атомы, вы получаете весьма запутанную картину молекулы. Атомы позволяют значительно упростить модель.
Боб Мартин в книге Чистый код описывает один из запахов кода: вызов методов разного уровня детализации. Этот тот случай, когда декомпозируя молекулы, программист иногда работает с ними как с набором атомов, а иногда, как с набором элементарных частиц.
Скорее всего в данном случае можно отказаться от пятнадцати классов, в пользу трёх-четырёх, каждый из которых состоит из трёх-четырёх более мелких классов.
Количество классов у вас увеличится, поскольку появятся промежуточные; зато каждый из них теперь будет простым для понимания.
С другой стороны, бывают ситуации, когда большое количество параметров вполне допустимо. Мартин Фаулер описал паттерн Registry (Реестр), который предоставляет доступ к набору однотипных объектов. Скажем, вам нужно 5 или 6 репозиториев и, вместо того, чтобы передавать их по одному, вы заводите реестр репозиториев и передаёте только один этот объект. При этом у самого реестра в качестве параметров конструктора теперь передаются все репозитории, которые есть в вашей программе. Поскольку все репозитории относятся к одной категории объектов, код реестра получается простым и понятным. При этом конструктор реестра имеет 15-20 параметров и это всё равно выглядят ужасно. Я бы назвал этот случай неизбежным злом, и отнёс бы его причину к ограниченным выразительным средствам языка. В общем, иногда мы просто вынуждены писать так, потому что по другому язык не позволяет. Но будьте осторожны — прежде чем решить, что всё с вашим кодом в порядке, проверьте, что речь не идёт о первом случае: божественном объекте и смешении уровней детализации.

Комментариев нет:

Отправить комментарий