In questo caso, direi che la risposta ideale è che dipende da come vengono consumati gli enum, ma che nella maggior parte dei casi è probabilmente meglio definire tutti gli enum separatamente, ma se qualcuno di essi è già accoppiato in base alla progettazione, è necessario fornire un mezzi per introdurre collettivamente detti enum accoppiati. In effetti, hai una tolleranza di accoppiamento fino alla quantità di accoppiamento intenzionale già presente, ma non di più.
Considerando ciò, è probabile che la soluzione più flessibile definisca ogni enum in un file separato, ma fornisca pacchetti accoppiati quando è ragionevole farlo (come determinato dall'uso previsto degli enum coinvolti).
La definizione di tutte le enumerazioni nello stesso file le accoppia insieme e per estensione fa sì che qualsiasi codice che dipende da uno o più enum dipenda da tutti gli enum, indipendentemente dal fatto che il codice utilizzi effettivamente altri enum.
#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()
preferirei solo conoscerlo map_t
, perché altrimenti qualsiasi modifica agli altri lo influenzerà anche se in realtà non interagisce con gli altri.
#include "mapEnum.h" // Theoretical file defining map_t.
void renderMap(map_t, mapIndex);
Tuttavia, nel caso in cui i componenti siano già accoppiati insieme, fornire più enum in un singolo pacchetto può facilmente fornire ulteriore chiarezza e semplicità, a condizione che vi sia una chiara ragione logica per cui gli enum possano essere accoppiati, che anche l'uso di quegli enum sia accoppiato, e che fornirli non introduce alcun accoppiamento aggiuntivo.
#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);
In questo caso, non esiste una connessione logica diretta tra il tipo di entità e il tipo di materiale (presupponendo che le entità non siano costituite da uno dei materiali definiti). Se, tuttavia, abbiamo avuto un caso in cui, ad esempio, un enum è esplicitamente dipendente dall'altro, allora ha senso fornire un singolo pacchetto contenente tutti gli enum accoppiati (così come qualsiasi altro componente accoppiato), in modo che l'accoppiamento possa essere isolato per quel pacchetto quanto è ragionevolmente possibile.
// 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()];
}
Ma ahimè ... anche quando due enum sono intrinsecamente accoppiati insieme, anche se è qualcosa di forte come "il secondo enum fornisce sottocategorie per il primo enum", potrebbe ancora venire un momento in cui è necessario solo uno degli enum.
#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;
}
Pertanto, poiché sappiamo sia che possono sempre esserci situazioni in cui la definizione di più enumerazioni in un singolo file può aggiungere un accoppiamento non necessario e che la fornitura di enumerazioni accoppiate in un singolo pacchetto può chiarire l'uso previsto e consentirci di isolare il codice di accoppiamento stesso come per quanto possibile, la soluzione ideale è definire ciascuna enumerazione separatamente e fornire pacchetti congiunti per tutti gli enum che sono destinati a essere usati frequentemente insieme. Gli unici enumerati nello stesso file saranno quelli intrinsecamente collegati tra loro, in modo tale che l'uso dell'uno richieda anche l'uso dell'altro.
// 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"