6

Let's say we have a class with many methods that do something different but can be grouped together as one "kind of functionality". For example, adding a configuration o setting rules up.

Let's go with the rules example. Say we have a class that models a board game, and we have add different rules so when the game is played the rules are ensured:

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() { /*...*/ }
}

This is just an example I just came up with. The actual model is something different but too hard to explain here. The idea and structure, though, is the same than in the example.

I would like to extract all those setupXRule() methods somehow into just unit, in term of design. Reasons:

  • Makes code clearer
  • The rules of the game are not fixed and "hardcoded" in the game class
  • Additional rules can be added. Here's what I meant with generalization. I would want any other programmer using this class to define his or her own rules and setting them on the game.

What would be the best approach?

Update: I have been thinking about this design:

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);
    }
}

And then we have different rules:

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
    }
}
  • Nice question. A Factory comes to mind, one which would allow other software developers to register new methods with it, but it's unclear how those methods would interact with your game internals. Instead of calling separate methods, you could use setupRule("SinglePlayer"); Are you sure this isn't a configuration problem, though? Providing a well thought-out configuration would allow others to simply encode their rules in an XML or JSON file. – Robert Harvey Apr 21 '16 at 15:17
  • No, this is definetly not a configuration problem. About the internals, how about what I included in my update? (check new update) – dabadaba Apr 21 '16 at 15:50
  • Ah, so you would instantiate a RuleManager in the new method? Then I think it comes down to registering all of the rules in a collection of delegates, and then cycling through the collection and running all of the rules during initialization. – Robert Harvey Apr 21 '16 at 15:51
  • Yes something like that. So how would I do what you suggested? – dabadaba Apr 21 '16 at 16:10
  • I would start looking at using interfaces if I were you. tutorials.jenkov.com/java/interfaces.html – Snoop Apr 21 '16 at 16:25
0

You need a collection that represents all known setup rules. An master array or list of interfaces (as @StevieV suggests), for example.

I'd put each setup capability into it's own class so that I could name all the methods simplysetup(). Each class would either inherit from a shared base class or implement an interface (or both). The base class and/or interface would have the setup() method.

You can populate the master list statically, manually, so you can control the order, or, put a static method in each class that creates an instance of itself and adds itself to the master list (easier to maintain perhaps, but no guarantee on ordering).

Then you need to use applicable rules for any given situation. So, I'd turn a situation into a first-class object.

So, the rule interface could include an boolean isApplicable(Situation situation) method, which you'd run to compose the applicable set for a given situation.

Each rule would have it's own way to determine if it is applicable, for example, if single player, if multi player, etc.. So the interface would have two methods: isApplicable(situation), and setup(). (Alternately, you could have just setup(situation), which would simply do nothing when not applicable.)

Presumably, setup() would do what is necessary, however, you can also build a secondary list for any given situation, if you like.

As @RobertHarey suggests, this can be done using lambda's as well, the master collection would be a list of lambdas or lambda pairs for the two methods.

  • Before this answer, I ended up implementing something that resembles this very much, butthe isApplicable method, which I don't see necessary. Check out my actual code, does it make sense? Is it like what you're saying? pastebin.com/DfCuevd8 – dabadaba Apr 21 '16 at 17:46
  • Static classes and methods are death to testability, and if the rules are responsible for adding themselves to the list, this adds an unnecessary dependency to the rules and an extra responsibility. – Amy Blankenship Apr 21 '16 at 18:47
  • @AmyBlankenship I am using no static methods or classes. An about the rules adding themselves, are you talking about the post() method? – dabadaba Apr 21 '16 at 18:53
  • @dabadaba, I think the comment is directed to (those who read) me for suggesting the possibility of using a one line static function to self-register. Statics are an appropriate concern: I've railed against them myself. – Erik Eidt Apr 21 '16 at 19:00
  • I was specifically referring to Erik's answer. But yes, I don't think your rules should take on the responsibility for adding themselves to the list. They have no reason to even know they are part of a list. – Amy Blankenship Apr 21 '16 at 19:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.