En este caso, diría que la respuesta ideal es que depende de cómo se consuman las enumeraciones, pero que en la mayoría de las circunstancias probablemente sea mejor definir todas las enumeraciones por separado, pero si alguna de ellas ya está unida por diseño, debe proporcionar un medios de introducir dichas enumeraciones acopladas colectivamente. En efecto, tiene una tolerancia de acoplamiento hasta la cantidad de acoplamiento intencional ya presente, pero no más.
Teniendo esto en cuenta, es probable que la solución más flexible defina cada enumeración en un archivo separado, pero proporcione paquetes acoplados cuando sea razonable hacerlo (según lo determine el uso previsto de las enumeraciones involucradas).
La definición de todas sus enumeraciones en el mismo archivo las une y, por extensión, hace que cualquier código que dependa de una o más enumeraciones dependa de todas las enumeraciones, independientemente de si el código realmente utiliza alguna otra enumeración.
#include "enumList.h"
// Draw map texture. Requires map_t.
// Not responsible for rendering entities, so doesn't require other enums.
// Introduces two unnecessary couplings.
void renderMap(map_t, mapIndex);
renderMap()
preferiría saberlo map_t
, porque de lo contrario, cualquier cambio en los demás lo afectará aunque en realidad no interactúe con los demás.
#include "mapEnum.h" // Theoretical file defining map_t.
void renderMap(map_t, mapIndex);
Sin embargo, en el caso de que los componentes ya estén acoplados entre sí, proporcionar múltiples enumeraciones en un solo paquete puede proporcionar claridad y simplicidad adicionales, siempre que haya una razón lógica clara para que las enumeraciones se acoplen, que el uso de esas enumeraciones también se acople, y que proporcionarlos tampoco introduce acoplamientos adicionales.
#include "entityEnum.h" // Theoretical file defining entity_t.
#include "materialsEnum.h" // Theoretical file defining materials_t.
// Can entity break the specified material?
bool canBreakMaterial(entity_t, materials_t);
En este caso, no existe una conexión directa y lógica entre el tipo de entidad y el tipo de material (suponiendo que las entidades no estén hechas de uno de los materiales definidos). Sin embargo, si tenemos un caso en el que, por ejemplo, una enumeración depende explícitamente de la otra, entonces tiene sentido proporcionar un solo paquete que contenga todas las enumeraciones acopladas (así como cualquier otro componente acoplado), de modo que el acoplamiento pueda ser aislado de ese paquete tanto como sea razonablemente posible.
// File: "actionEnums.h"
enum action_t { ATTACK, DEFEND, SKILL, ITEM }; // Action type.
enum skill_t { DAMAGE, HEAL, BUFF, DEBUFF, INFLICT, NONE }; // Skill subtype.
// -----
#include "actionTypes.h" // Provides action_t & skill_t from "actionEnums.h", and class Action (which couples them).
#include "entityEnum.h" // Theoretical file defining entity_t.
// Assume ActFlags is or acts as a table of flags indicating what is and isn't allowable, based on entity_t and Action.
ImplementationDetail ActFlags;
// Indicate whether a given type of entity can perform the specified action type.
// Assume class Action provides members type() and subtype(), corresponding to action_t and skill_t respectively.
// Is only slightly aware of the coupling; knows type() and subtype() are coupled, but not how or why they're coupled.
bool canAct(entity_t e, const Action& act) {
return ActFlags[e][act.type()][act.subtype()];
}
Pero, por desgracia ... incluso cuando dos enumeraciones están intrínsecamente juntas, incluso si es algo tan fuerte como "la segunda enumeración proporciona subcategorías para la primera enumeración", todavía puede llegar un momento en que solo una de las enumeraciones sea necesaria.
#include "actionEnums.h"
// Indicates whether a skill can be used from the menu screen, based on the skill's type.
// Isn't concerned with other action types, thus doesn't need to be coupled to them.
bool skillUsableOnMenu(skill_t);
// -----
// Or...
// -----
#include "actionEnums.h"
#include "gameModeEnum.h" // Defines enum gameMode_t, which includes MENU, CUTSCENE, FIELD, and BATTLE.
// Used to grey out blocked actions types, and render them unselectable.
// All actions are blocked in cutscene, or allowed in battle/on field.
// Skill and item usage is allowed in menu. Individual skills will be checked on attempted use.
// Isn't concerned with specific types of skills, only with broad categories.
bool actionBlockedByGameMode(gameMode_t mode, action_t act) {
if (mode == CUTSCENE) { return true; }
if (mode == MENU) { return (act == SKILL || act == ITEM); }
//assert(mode == BATTLE || mode == FIELD);
return false;
}
Por lo tanto, dado que sabemos que siempre puede haber situaciones en las que definir enumeraciones múltiples en un solo archivo puede agregar un acoplamiento innecesario, y que proporcionar enumeraciones acopladas en un solo paquete puede aclarar el uso previsto y permitirnos aislar el código de acoplamiento real como En la medida de lo posible, la solución ideal es definir cada enumeración por separado y proporcionar paquetes conjuntos para cualquier enumeración que se pretenda utilizar con frecuencia. Las únicas enumeraciones definidas en el mismo archivo serán las que están intrínsecamente vinculadas entre sí, de modo que el uso de uno requiere el uso del otro también.
// File: "materialsEnum.h"
enum materials_t { WOOD, STONE, ETC };
// -----
// File: "entityEnum.h"
enum entity_t { PLAYER, MONSTER };
// -----
// File: "mapEnum.h"
enum map_t { 2D, 3D };
// -----
// File: "actionTypesEnum.h"
enum action_t { ATTACK, DEFEND, SKILL, ITEM };
// -----
// File: "skillTypesEnum.h"
enum skill_t { DAMAGE, HEAL, BUFF, DEBUFF, INFLICT, NONE };
// -----
// File: "actionEnums.h"
#include "actionTypesEnum.h"
#include "skillTypesEnum.h"