Nesse caso, eu diria que a resposta ideal é que depende de como as enumerações são consumidas, mas na maioria das circunstâncias provavelmente é melhor definir todas as enumerações separadamente, mas se alguma delas já estiver acoplada pelo design, você deverá fornecer um meios de introduzir as referidas enumerações acopladas coletivamente. Com efeito, você tem uma tolerância de acoplamento até a quantidade de acoplamento intencional já presente, mas não mais.
Considerando isso, é provável que a solução mais flexível defina cada enum em um arquivo separado, mas forneça pacotes acoplados quando for razoável fazê-lo (conforme determinado pelo uso pretendido das enumerações envolvidas).
Definir todas as suas enumerações no mesmo arquivo as une e, por extensão, faz com que qualquer código que depende de uma ou mais enumerações dependa de todas as enumerações, independentemente de o código realmente usar outras enumerações.
#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()
preferiria apenas saber sobre isso map_t
, porque, caso contrário, qualquer alteração nos outros o afetará, mesmo que na verdade não interaja com os outros.
#include "mapEnum.h" // Theoretical file defining map_t.
void renderMap(map_t, mapIndex);
No entanto, no caso em que os componentes já estão acoplados, o fornecimento de várias enumerações em um único pacote pode facilmente fornecer clareza e simplicidade adicionais, desde que haja uma razão lógica clara para que as enumerações sejam acopladas, que o uso dessas enumerações também seja acoplado, e que fornecê-los também não introduz acoplamentos adicionais.
#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);
Nesse caso, não há conexão lógica direta entre o tipo de entidade e o tipo de material (supondo que as entidades não sejam feitas de um dos materiais definidos). Se, no entanto, tivermos um caso em que, por exemplo, um enum seja explicitamente dependente do outro, faz sentido fornecer um único pacote contendo todas as enumerações acopladas (assim como quaisquer outros componentes acoplados), para que o acoplamento possa ser isolado para esse pacote, tanto quanto for razoavelmente possível.
// 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()];
}
Mas, infelizmente ... mesmo quando duas enums estão intrinsecamente acopladas, mesmo que seja algo tão forte quanto "o segundo enum fornece subcategorias para o primeiro enum", ainda pode chegar um momento em que apenas um dos enums é necessário.
#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;
}
Portanto, como sabemos que sempre pode haver situações em que a definição de várias enumerações em um único arquivo pode adicionar acoplamento desnecessário e que o fornecimento de enumerações em um único pacote pode esclarecer o uso pretendido e nos permitir isolar o próprio código de acoplamento como Na medida do possível, a solução ideal é definir cada enumeração separadamente e fornecer pacotes conjuntos para quaisquer enumerações que se destinam a serem frequentemente usadas juntas. As únicas enumerações definidas no mesmo arquivo serão aquelas intrinsecamente ligadas, de modo que o uso de um também exija o uso do outro.
// 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"