В этом случае, я бы сказал, что идеальный ответ заключается в том, что это зависит от того, как используются перечисления, но в большинстве случаев, вероятно, лучше определить все перечисления по отдельности, но если какой-либо из них уже связан по проекту, вы должны предоставить средство совместного введения упомянутых связанных перечислений. По сути, у вас уже есть допуск на связывание до количества преднамеренного связывания, но не более.
Учитывая это, наиболее гибкое решение, скорее всего, определит каждое перечисление в отдельном файле, но предоставит связанные пакеты, когда это целесообразно сделать (что определяется предполагаемым использованием задействованных перечислений).
Определение всех ваших перечислений в одном и том же файле объединяет их вместе, и, соответственно, любой код, который зависит от одного или нескольких перечислений, зависит от всех перечислений, независимо от того, использует ли код какие-либо другие перечисления.
#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()
Скорее всего, об этом знают map_t
, потому что в противном случае любые изменения в других будут влиять на него, даже если он на самом деле не взаимодействует с другими.
#include "mapEnum.h" // Theoretical file defining map_t.
void renderMap(map_t, mapIndex);
Однако в случае, когда компоненты уже связаны друг с другом, предоставление нескольких перечислений в одном пакете может легко обеспечить дополнительную ясность и простоту, при условии, что есть очевидная логическая причина для объединения перечислений, что использование этих перечислений также связано, и что их предоставление также не вводит никаких дополнительных соединений.
#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);
В этом случае нет прямой логической связи между типом объекта и типом материала (при условии, что объекты не сделаны из одного из определенных материалов). Однако, если у нас был случай, когда, например, одно перечисление явно зависит от другого, то имеет смысл предоставить единый пакет, содержащий все связанные перечисления (а также любые другие связанные компоненты), так что связь может быть изолированы от этой упаковки настолько, насколько это возможно.
// 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()];
}
Но, увы ... даже когда два перечисления по своей сути связаны друг с другом, даже если это что-то столь же сильное, как «второе перечисление предоставляет подкатегории для первого перечисления», может все же наступить момент, когда необходимо только одно из перечислений.
#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;
}
Следовательно, поскольку мы знаем и то, что всегда могут быть ситуации, когда определение нескольких перечислений в одном файле может добавить ненужную связь, и что предоставление связанных перечислений в одном пакете может прояснить предполагаемое использование и позволить нам изолировать сам фактический код связи как Насколько это возможно, идеальным решением является определение каждого перечисления отдельно и предоставление совместных пакетов для любых перечислений, которые предназначены для частого использования вместе. Единственными перечислениями, определенными в одном и том же файле, будут те, которые неразрывно связаны друг с другом, так что использование одного также требует использования другого.
// 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"