Sto tentando di modellare un gioco di carte in cui le carte hanno due importanti set di funzionalità:
Il primo è un effetto. Queste sono le modifiche allo stato del gioco che si verificano quando giochi la carta. L'interfaccia per l'effetto è la seguente:
boolean isPlayable(Player p, GameState gs);
void play(Player p, GameState gs);
E potresti considerare la carta giocabile se e solo se riesci a far fronte al suo costo e tutti i suoi effetti sono giocabili. Così:
// in Card class
boolean isPlayable(Player p, GameState gs) {
if(p.resource < this.cost) return false;
for(Effect e : this.effects) {
if(!e.isPlayable(p,gs)) return false;
}
return true;
}
Ok, finora, abbastanza semplice.
L'altro set di funzioni sulla carta sono le abilità. Queste abilità sono modifiche allo stato del gioco che puoi attivare a piacimento. Quando ho trovato l'interfaccia per questi, mi sono reso conto che avevano bisogno di un metodo per determinare se possono essere attivati o meno, e un metodo per implementare l'attivazione. Finisce per essere
boolean isActivatable(Player p, GameState gs);
void activate(Player p, GameState gs);
E mi rendo conto che con l'eccezione di chiamarlo "attiva" invece di "giocare", Ability
e Effect
hanno la stessa identica firma.
È una brutta cosa avere più interfacce con una firma identica? Dovrei semplicemente usarne uno e avere due set della stessa interfaccia? Come così:
Set<Effect> effects;
Set<Effect> abilities;
In tal caso, quali passi di refactoring dovrei intraprendere se diventano non identici (poiché vengono rilasciate più funzionalità), in particolare se sono divergenti (ovvero entrambi ottengono qualcosa che l'altro non dovrebbe, al contrario di un solo guadagno e l'altro essendo un sottoinsieme completo)? Sono particolarmente preoccupato che la loro combinazione non sarà sostenibile non appena qualcosa cambierà.
La stampa fine:
Riconosco che questa domanda è generata dallo sviluppo del gioco, ma ritengo che sia il tipo di problema che potrebbe insinuarsi facilmente nello sviluppo di un gioco, in particolare quando si tenta di accogliere i modelli di business di più client in un'applicazione come accade quasi ogni progetto che abbia mai fatto con più di un'influenza aziendale ... Inoltre, i frammenti utilizzati sono frammenti Java, ma questo potrebbe facilmente applicarsi a una moltitudine di linguaggi orientati agli oggetti.