Как я могу написать контроллер, не превращая его в объект Бога?
В моем приложении у меня есть Controller
это началось основным методом. Контроллер инициализирует хуки, соединения с базой данных, пользовательский интерфейс, другое соединение и другие вещи. Он содержит большую часть состояния программы (нет, это не синглтон). В другом примере есть контроллер для бота, который обрабатывает интерпретацию и отправку команд. Оба довольно большие файлы.
Я читал об объектах Бога, но я не знаю, как это разделить. Если я разделю переводчика и диспетчера в боте, это приведет к ужасной цепочке вызовов (что-то вроде getBot().getParser().getOutput().sendMessage(recipient, message)
). Аналогично, в первом Контроллере, если я разделю вещи, у вас просто будут объекты Data, которые содержат поля, и некоторые вспомогательные методы-псевдонимы. Разделение их только ухудшит ситуацию. И прежде чем вы предположите, что это не поддерживаемо, на самом деле это не так. Я даже не написал контроллер Bot, но я все еще знаю, что происходит.
Однако проблема в том, что класс Bot имеет длину 2000 строк (возможно, короче, если я убрал комментарии Javadoc), а длина Bot составляет примерно 1000 строк. Много линий = объект Бога. Но нормально ли это для одного или двух основных классов проекта?
4 ответа
"Много строк" вовсе не означает, что класс - это божественный объект, это ужасный ужасный критерий для определения того, следует ли вам что-то реорганизовать. Некоторые вещи очень сложны и требуют сложного и изначально большого объекта. Идея объекта Бога - это то, что делает класс.
Например, если бы я сделал объект, который мог
DoMyTaxes()
GiveMeHugs()
LogThisError()
StartGameLoop()
Объект будет квалифицироваться как объект бога, даже если это может быть только 100 строк кода. Основная идея заключается в том, что все вышеперечисленное совершенно не связано (в конце бизнес-логики спектра), так почему же в мире они все являются частью одного и того же объекта. Если бы я решил, что объятия будут длиться дольше, я мог бы в конечном итоге поднять налоги. Введите IRS.
Однако, если вы работаете на симуляторе физики, скажем, и Classical()
класс будет иметь методы / объекты, такие как:
Space()
Time()
Velocity()
Speed()
Mass()
Acceleration()
Gravity()
Force()
Impulse()
Torque()
Momentum()
AngularMomentum()
Inertia()
MomentOfInertia()
ReferenceFrame()
Energy()
KineticEnergy()
PotentialEnergy()
MechanicalWork()
VirtualWork()
DAlembertsPrinciple()
(любезно предоставлено Википедией)
Этот объект не будет объектом бога. Это сложный объект. Все, что имеет отношение к ньютоновской физике, проходит через это, но это не объект Бога... это просто действительно большой объект. Выше может быть тысячи строк кода.
Quantum()
Само собой разумеется, объект будет еще более сложным.
Повторим еще раз: идея касается поведения программы, а не потока данных:
вас не волнует, содержит ли один объект много данных приложения, или же большинству потоков приходится проходить через один объект. Что больше влияет на ремонтопригодность, так это когда один класс Бога (tm) содержит слишком много поведения (бизнес-код).
Если вы думаете, что есть проблема, вы можете попытаться реализовать различные формы посредничества или более уродливые шаблоны, такие как внедрение зависимостей.
Если вас не устраивает размер и сложность класса, то обычно это хороший показатель того, что можно сделать лучший дизайн. Но не измеряйте только по размеру. Если класс легко понять и следовать, но он содержит много кода, это не обязательно означает, что он является кандидатом на рефакторинг. Я видел, как люди увлекались этим, и беспорядок, который они создавали в стремлении сделать вещи маленькими, был намного хуже, чем в исходном коде. С другой стороны, я прочитал классы от конца до конца несколько раз и все еще не знал, что они делают.
Вопрос, который я задам, - если я передам это другому разработчику, смогут ли они легко понять и поддерживать его?
Если ответ да, то есть вероятность, что вам не нужно ничего делать. Если нет, то рефакторинг в порядке.
Что касается божьих объектов, читая ваш пост, похоже, этот класс делает слишком много. Мне интересно, если вы могли бы сначала преобразовать состояние в набор объектов модели в качестве отправной точки. Тогда ваш класс начинает выглядеть как фабрика конфигураций.
Я хотел бы предложить, чтобы физический / двигательный механизм определенно был отделен от переводчика языка; хотя интерпретатору языка потребуется доступ к некоторым общедоступным методам и свойствам физического движка, нет никаких причин, по которым два аспекта робота должны быть в одном классе. Сам языковой переводчик можно разделить на несколько классов, как и движок. Может существовать объект master-control, но он должен иметь относительно небольшой объем кода. Он, основной движущий движок и основной языковой движок, должен все делегировать большую часть своей работы объектам, которые их составляют.
Я думаю, что ключевым принципом здесь является "сплоченность".
DoMyTaxes()
GiveMeHugs()
LogThisError()
StartGameLoop()
..не связно
Что-то вроде:
GiveMeHug()
GiveMeKisses()
GiveMeHugs(int noOfTimes)
GiveMeHugs(int noOfTimes, Person person)
GiveMeHugsAndKisses()
..связны, так как все методы довольно похожи. Вы можете иметь 1000 связных методов в классе, и он все равно не будет объектом бога, поскольку ответственность за класс все еще ограничена.