Diversi algoritmi di punteggio per diversi elementi di competizione

3

Sto creando un sistema di punteggio per una competizione che è alquanto oscura, ma assomiglia alle Olimpiadi in termini di struttura ad alto livello. Pertanto, farò la mia domanda in termini di una versione astratta e fittizia delle Olimpiadi, poiché tutti possono identificarsi in qualche modo.

Assumi la seguente gerarchia di classi e rollup dei punteggi:

  • La classe evento ha uno o più sport (ad esempio, le Olimpiadi del 2012 hanno Decathlon, IndividualMedley, ecc.) e uno o più eventi (un EventScore per squadra per evento calcolato sommando gli SportScores del team per un particolare evento)
  • Le classi sportive hanno uno o più elementi (ad esempio, Decathlon ha Shotput, Javelin, ecc.) e uno o più SportScores (un punteggio per squadra per sport calcolato sommando gli ElementScores del team per uno sport particolare)
  • La classe elemento ha uno o più round (ad esempio, Shotput ha Throw1, Throw2, ecc.) e uno o più ElementScores (un ElementScore per Team per Element calcolato sommando i RoundScores del team per un elemento particolare)

L'algoritmo del punteggio (chiamiamolo metodo CalculateRoundScore ()) di un RoundScore particolare dipende dall'elemento a cui appartiene il round. Esempi:

  • Elemento Shotput: CalculateRoundScore (double ThrowDuration, double ThrowDistance, double GruntVolume) {algoritmo; }
  • Elemento Javelin: CalculateRoundScore (double ThrowDuration, double ThrowDistance, double GruntVolume) {algoritmo (diverso dall'algoritmo Shotput anche se i parametri sono gli stessi, che sembrerebbe eliminare il sovraccarico come un'opzione praticabile); }
  • 100MeterDash element: CalculateRoundScore (double Time, bool FalseStart) {algoritmo; }

Sebbene io stia cercando una guida generale all'architettura, ecco alcune delle mie domande specifiche:

  • Come faccio ad associare diversi metodi di CalculateRoundScore a diversi elementi?
  • Devo usare interfacce, ereditarietà, sovraccarico o qualche altro approccio?
  • In quale classe (i) dovrebbero essere posizionati i vari metodi di CalculateRoundScore?

Concettualmente, posso immaginare che ogni elemento sia un'interfaccia ICalculateRoundScore. Tuttavia, ciò ha senso solo se creo una classe diversa per ciascun elemento diverso, il che non sembra giusto. Sembra che io abbia bisogno di una sorta di ricerca in cui la classe Round scelga il suo particolare metodo CalculateRoundScore a seconda dell'elemento a cui appartiene, ma non sono sicuro quale sarebbe il modo corretto orientato agli oggetti per farlo.

    
posta MikeyWazz 24.04.2014 - 17:23
fonte

1 risposta

4

However, that only makes sense if I create a different class for each different element, which doesn't seem right

Per me, questo sembra perfettamente giusto, poiché è solo un'applicazione del classico schema "strategia" ( in questo caso a RoundScoreCalculationStrategy ). Lo disegnerei in questo modo:

 interface RoundScoreCalculationStrategy
 {
     double Calculcate(Measurements m);
 }

Gli oggetti strategici possono essere facilmente inseriti in qualsiasi tipo di tabella di ricerca. Measurements sarà un tipo di base (o interfaccia) per incapsulare i possibili risultati di un round in uno dei tuoi eventi sportivi (come la tupla ThrowDuration, ThrowDistance, GruntVolume ) - così puoi separare la fornitura di quei valori dal calcolo del punteggio. Devi ancora costruire diversi oggetti di misura con diversi parametri del costruttore, ma ora puoi

  • costruisci quegli oggetti nel posto in codice dove "fai il giro" (che può essere un posto completamente diverso da dove avviene il punteggio)
  • riutilizzare gli stessi oggetti Measurement se contengono le stesse tuple dei parametri (ad esempio, per Shotput e Javelin), anche se il calcolo del punteggio è diverso

Naturalmente, potresti prendere in considerazione l'uso di funzioni delegate invece di oggetti RoundScoreCalculationStrategy diversi (il che può causare meno codice se ognuno degli algoritmi di calcolo del punteggio è solo una piccola funzione), ma l'idea principale mantiene lo stesso.

Una cosa da aggiungere: forse è sufficiente non distinguere tra le classi Strategy e le classi "Element". Le tue diverse discipline (che hai chiamato Elementi sopra) potrebbero ottenere una classe base virtuale comune Discipline - (potrebbe anche essere un'interfaccia), dove CalculateScore(Measurements m) è solo un metodo virtuale di quella classe base e Shotput , Javelin ecc. sono sottoclassi di Discipline con diverse implementazioni di quel metodo.

    
risposta data 24.04.2014 - 20:30
fonte