Разбиение на файлы - сколько стоит расщепление?

9

Если я скажу, что у меня есть иерархическая структура сущностей, а не компонентная модель. Что-то вроде:
(Да, это сделано)

Weapon-> Gun-> AutomaticGun-> MP44
Или, более классический пример:
Entity-> MovableEntity-> Enemy-> WalkingEnemy

Как далеко вы разделите исходные / заголовочные файлы для удобства чтения и организации? Лучше ли использовать что-то вроде Entity.cpp, MovableEntity.cpp, Enemy.cpp и т. Д., Или будет лучше подход Entity.cpp [содержащий Entity и MovableEntity] и Enemy.cpp [содержащий Enemy и WalkingEnemy]? (Или, в более независимом от языка формате, файл Enemy и файл Entity против файла для каждого класса?)
Кроме того, это может повлиять на что-либо, кроме читабельности и организации?

Коммунистическая утка
источник
1
Nitpicky, но я не думаю, что language-agnosticэто подходящий тег, поскольку он сильно зависит от языка, который вы используете для побочных эффектов.
Тетрад
Хороший вопрос, я думаю, что могу поменять.
Коммунистическая утка

Ответы:

12

Это полностью вопрос предпочтений. Тем не менее, я лично считаю, что лучше ошибиться в сторону большего количества файлов. Java требует один класс на файл, например , имя файла совпадает с именем класса; они делают это в соответствии с политикой, чтобы применить эту хорошую практику (хотя у вас могут быть подклассы, которые в основном обходят это).

Кроме того, системы управления исходным кодом довольно хороши для объединения изменений в файле, но это не составит труда, если вы просто работаете в совершенно отдельных файлах. Вы также можете легко увидеть, кто изменил какой класс. Допустим, другой разработчик вносит изменения в файл AllEntities.h; Вы не имеете ни малейшего понятия, какую именно сущность (или сущности) он изменил, пока не откроете файл и не посмотрите на вывод diff.

Однако здорово объединить небольшие структуры и перечисления, связанные с классом, в файл одного класса . Если у вас есть enum, который используется только одним классом, зачем разбивать его на собственный файл? Просто соедините их. Но если он используется другим классом (т. Е. Другой член класса относится к типу этого перечисления), тогда наступает время передать ему свой собственный файл.

Ricket
источник
Согласовано. Сложность ваших типов определенно должна быть фактором. Если ваш язык поддерживает частичные классы (или если реализации членов могут быть организованы аналогично C ++), я бы даже рекомендовал разбивать особо сложные типы на несколько файлов. Например, если есть (большой) интерфейс, который должен реализовать ваш класс, но код довольно общий и не очень релевантный для остальных, вы можете разбить этот код на отдельный файловый / частичный класс. Для типов перечислений, я думаю, вы могли бы с легкостью поместить все перечисления для данного пространства имен в один файл.
Майк Штробель
1
Разве группировка ваших перечислений не означает, что изменение одного значения приведет к перекомпиляции каждого файла, который использует перечисление в этом пространстве имен?
Коммунистическая утка
Ну, это действительно зависит от языка, но да, это, безусловно, может иметь такой эффект. Для меня это не проблема, так как я разрабатываю в основном на C # (без компиляции файлов за файлом), но это может быть проблематично в C ++ и других языках. Как всегда, необходимо учитывать факторы, зависящие от языка, и это будет одним из них :).
Майк Штробель
2

Многие языки вне C / C ++ накладывают ограничения на файлы. Рикет упомянул Java «один класс на файл»; Python использует файлы как пространства имен; другие языки часто копируют дух тех.

Если вы используете C или C ++, большее количество включенных файлов обычно означает более длительное время компиляции для каждого файла; с другой стороны, меньше значит больше перекомпилировать при внесении небольших изменений. Поскольку перечисления не могут быть заранее объявлены в C, вы всегда должны помещать их в заголовочные файлы, содержащие только другие перечисления, для разумности зависимостей.

В противном случае разумно использовать «один файл на класс» в Java, но долгое время Java поддерживала внутренние классы - например, контейнер и внутренний класс его итератора. Точно так же на любом другом языке вы, вероятно, захотите одну доминирующую запись / struct / class / type / interface / blorb на заголовок, но можете также решить включить связанные помощники или контейнеры.

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


источник
Я использовал иерархию в качестве примера; Я чувствовал, что это подчеркивает, что я имел в виду лучше. В реальном коде я стремлюсь к компонентам.
Коммунистическая утка