Tournament Module: Refactoring: MatchScorerFactory class
To follow along, you can check out the tournament-match-scorer-factory branch from the git repo: https://github.com/stephenaument/tactical-refactoring
$ git clone [email protected]:stephenaument/tactical-refactoring.git # If you haven't done this already $ git checkout tournament-match-scorer-factory
Now, let’s finish improving our MatchScorerFactory class.
Looking at the scorer method, I see a couple of things that I want to change.
First, we still have our if/else block. We’ve isolated it to this factory class. And while that’s an improvement over what we had, there is a better way to handle this by establishing a convention that maps our outcome values to class names.
This will allow us to add any number of possible outcomes without ever having to touch this class again.
But before we implement that, I want to address this code duplication I see. Notice how in the branches of our if/else block, we have almost identical code? The only difference being the class names?
Let’s separate out the logic for giving us the appropriate scorer class from the behavior that returns an instance of that class.
By taking this step now, it will isolate the changes we need to make to implement our convention-based approach.
First, I’ll write the code that I want: scorer_class.new match.
Next, I’ll move my if/else block to a new method named scorer_class, and I’ll remove the call to new, and simply return the class name that I want.
I’m going to convert the else to an explicit elsif to more clearly see what I’m dealing with.
Now I can see that I’m dealing with three cases: win, loss, draw. I can also see that I’ve already used an implicit convention when naming my scorer classes. I named it this way to make it easier to know which was which and to make it clear how they related to one another.
But by naming them this way, I now see another advantage. By taking my outcome string, capitalizing it, and appending Scorer to the end, I will have a string that matches my class name. Now, if I hadn’t exactly followed this naming convention, I could change the class names at this point, to make them match.
But we need to return a class, not a class name.
In Ruby, we can use Object.const_get to turn our class name string into the constant that points to our class.
Now, when I come back to add a descriptive comment to this class at the end, I’ll be sure to describe this convention and provide a couple of examples.
Oh, I see one final thing.
Our scorer_class method is handling two responsibilities at the moment. It’s getting the constant for the scorer class based on the scorer class name, but it’s also generating the scorer class name.
Let’s name that second bit and move it to its own method.
Next we will continue with the TeamStat class.