Estrazione e generalizzazione di metodi "ripetuti" con funzionalità simili

7

Diciamo che abbiamo una classe con molti metodi che fanno qualcosa di diverso ma possono essere raggruppati insieme come un "tipo di funzionalità". Ad esempio, aggiungendo una configurazione o impostando le regole.

Andiamo con l'esempio delle regole. Diciamo che abbiamo una classe che modella un gioco da tavolo, e abbiamo aggiunto regole diverse, quindi quando il gioco è giocato le regole sono garantite:

public class Game {
    private RuleManager ruleManager;
    // etc...

    public Game() {
        ruleManager = new RuleManager(this);
        setupGameRules();
        // etc...
    }

    private setupGameRules() {
        if (players.size() == 1)
            setupSinglePlayerRule();
        else
            setupMultiplePlayerRule();

        setupNumberOfTurnsRule();

        setupScoreRule();
    }

    private void setupSinglePlayerRule() { /*...*/ }
    private void setupMultiplePlayerRule() { /*...*/ }
    private void setupNumberOfTurnsRule() { /*...*/ }
    private void setupScoreRule() { /*...*/ }
}

Questo è solo un esempio che mi è appena venuto in mente. Il modello attuale è qualcosa di diverso ma troppo difficile da spiegare qui. L'idea e la struttura, tuttavia, sono le stesse che nell'esempio.

Vorrei estrarre tutti quei metodi setupXRule() in qualche modo in unità, in termini di design. Motivi:

  • Rende il codice più chiaro
  • Le regole del gioco non sono fisse e "hardcoded" nella classe di gioco
  • È possibile aggiungere ulteriori regole. Ecco cosa intendevo con generalizzazione. Vorrei che qualsiasi altro programmatore utilizzi questa classe per definire le proprie regole e impostarle sul gioco.

Quale sarebbe l'approccio migliore?

Aggiornamento: ho pensato a questo progetto:

public abstract class GameRule {
    protected Game game;
    protected RulesManager rulesManager;
    protected Rule[] rules;

    public GameRule(Game g) {
        game = g;
        rulesManager = g.getRulesManager();
    }

    // Sets up the rule
    protected abstract void build();

    // Posts the rule to the game, so when it's played the rule is enforced
    public void post() {
        if (rules == null)
            throw new IllegalStateException("The rules have not beein initialized yet.");

        rulesManager.post(rules);
    }
}

E poi abbiamo regole diverse:

public class SinglePlayerRule extends GameRule {

    public SinglePlayerRule(Game g) {
        super(g);
        build();
    }

    protected void build() {
        // sets up the rule using the rule manager internal operation to handle and manage rules
    }
}
    
posta dabadaba 21.04.2016 - 16:31
fonte

1 risposta

0

Hai bisogno di una collezione che rappresenti tutte le regole di setup conosciute. Un array master o un elenco di interfacce (come suggerisce @StevieV), ad esempio.

Metterei ogni funzionalità di configurazione nella propria classe in modo che potessi nominare tutti i metodi semplicemente setup() . Ogni classe erediterebbe da una classe base condivisa o implementerebbe un'interfaccia (o entrambe). La classe base e / o l'interfaccia avrebbero il metodo setup() .

È possibile popolare l'elenco principale in modo statico, manuale, in modo da poter controllare l'ordine, oppure, inserire un metodo statico in ogni classe che crea un'istanza di se stesso e si aggiunge all'elenco principale (più facile da gestire forse, ma non garanzia per l'ordine).

Quindi devi usare le regole applicabili per ogni situazione specifica. Quindi, trasformo una situazione in un oggetto di prima classe.

Quindi, l'interfaccia della regola potrebbe includere un metodo boolean isApplicable(Situation situation) , che dovresti eseguire per comporre il set applicabile per una determinata situazione.

Ogni regola avrebbe il suo modo di determinare se è applicabile, ad esempio, se giocatore singolo, se multigiocatore, ecc. Quindi l'interfaccia avrebbe due metodi: isApplicable(situation) e setup() . (In alternativa, potresti avere solo setup(situation) , che non farebbe semplicemente nulla se non applicabile.)

Presumibilmente, setup() farebbe ciò che è necessario, tuttavia, se lo desideri, puoi anche creare un elenco secondario per ogni situazione.

Come suggerisce @RobertHarey, questo può essere fatto usando anche lambda, la collezione master sarebbe una lista di coppie lambda o lambda per i due metodi.

    
risposta data 21.04.2016 - 19:16
fonte

Leggi altre domande sui tag