9
\$\begingroup\$

If I say I have a hierarchal entity framework, rather than a component model. Something like:
(Yes, this is made up)

Weapon->Gun->AutomaticGun->MP44
Or, more of a classical example:
Entity->MovableEntity->Enemy->WalkingEnemy

How far would you split up the source/header files for readability and organization? Is it best to go something like Entity.cpp, MovableEntity.cpp, Enemy.cpp, etc. or would an approach like Entity.cpp [containing Entity and MovableEntity] and Enemy.cpp [containing Enemy and WalkingEnemy] be better? (Or in a more language agnostic way, an Enemy file and an Entity file vs a file for each class?)
Also, would this affect anything other than readability and organization?

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Nitpicky, but I don't think language-agnostic is an appropriate tag since it depends greatly on the language you're using as to the side effects. \$\endgroup\$
    – Tetrad
    Commented Aug 9, 2010 at 18:11
  • \$\begingroup\$ Good point, I think I can retag. \$\endgroup\$ Commented Aug 9, 2010 at 18:14

2 Answers 2

12
\$\begingroup\$

This is entirely a matter of preference. However, I personally believe it is best to err on the side of more files. Java requires one class per file, with the filename the same as the class name, for example; they do this by policy to enforce this good practice (though you can have subclasses which basically get around this).

Also, source control systems are pretty good at merging changes in a file, but it's less of a hassle if you're just working in totally separate files. You can also easier see who changed which class. Let's say another developer makes a change to the file AllEntities.h; you have no clue exactly what entity (or entities) he changed until you open the file and look at the diff output.

It's great to group small structs and enums related to class within one class's file, though. If you have an enum that's only used by a single class, why split it into its own file? Just put them together. But if it's used by another class (i.e. another class member is of this enum's type), that's when it is time to give it its own file.

\$\endgroup\$
3
  • \$\begingroup\$ Agreed. Complexity of your types should definitely be a factor. If your language supports partial classes (or if member implementations can be organized similarly to C++), then I would even recommend breaking up particularly complex types into multiple files. For example, if there's a (large) interface that your class must implement, but the code is fairly generic and not terribly relevant to the rest, you could break that code out into a separate file/partial class. For enum types, I think you could get away with placing all enums for a given namespace within a single file. \$\endgroup\$ Commented Aug 9, 2010 at 19:09
  • 1
    \$\begingroup\$ Doesn't grouping your enums mean changing a single value would cause a recompile of every file that uses an enum in that namespace? \$\endgroup\$ Commented Aug 9, 2010 at 21:00
  • \$\begingroup\$ Well, that really depends on the language, but yes, it could certainly have that effect. It's not really an issue for me, as I develop primarily in C# (no file-by-file compilation), but it could be problematic in C++ and other languages. As always, there are language-specific factors to consider, and that would be one of them :). \$\endgroup\$ Commented Aug 9, 2010 at 21:28
2
\$\begingroup\$

Many languages outside of C/C++ impose constraints on files. Ricket mentioned Java's 'one class per file'; Python uses files as namespaces; other languages often copy the spirit of those.

If you are using C or C++, more included files generally means longer compile times per file; on the other hand, fewer means more to recompile when making small changes. Because enumerations cannot be forward-declared in C, you should always put them into header files containing only other enums, for dependency sanity.

Otherwise, Java's "one file per class" is reasonable, but for a long time Java has supported inner classes - like a container, and an inner class of its iterator. Similarly in any other language you'll probably want one dominant record/struct/class/type/interface/blorb per header, but may decide to include related helpers or containers as well.

(You don't need to use a component model, but if you have a deep and specific class hierarchy like that, you are going to hate yourself later.)

\$\endgroup\$
1
  • \$\begingroup\$ I was using the hierarchy as an example; I felt it did emphasise what I meant better. In actual code, I'm striving towards components. \$\endgroup\$ Commented Aug 9, 2010 at 17:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .