Refactoring: Creating an abstract parent
I have been implementing MiniMax in Java for my TicTacToe game. Once I had this up and running, I wanted to add Alpha Beta pruning, which makes the MiniMax algorithm more efficient. Whilst I will try to summarise the details of how I implemented Alpha Beta pruning and why its faster in a future post, today I wanted to run through how I refactored my two concrete classes into two abstract classes.
Because Alpha Beta Pruning is an optimisation of MiniMax rather than a new algorithm, I started by copying my
MiniMax class to a new
AlphaBeta class and then adding the optimisation to it. Once completed, I then had two different classes which shared a similar structure but had some different implementations. There was clear code duplication, which is a code smell, so I decided to refactor both classes to use the same parent class, which could hold all the shared properties and methods. Because this parent class could not work alone, I knew it needed to be an abstract class.
Here’s how I did it:
Step 1: Renamed MiniMax to SimpleMiniMax (as I wanted the Abstract parent class to be called
MiniMax, which is the name of both concrete implementations underlying algorithm).
Step 2: With my cursor in the AlphaBeta class, I selected
Refactor > Extract > SuperClass.
Step 3: In the dialogue box, I selected all the properties and methods I wanted to pull up from
AlphaBeta to the
MiniMax abstract class: which were all the properties and methods directly replicated in
SimpleMiniMax. I then selected all methods which had the same signature in the two concrete sub-classes but had different implementations and made them abstract methods.
Step 4: Ran the tests and checked that
AlphaBeta was still working, which it was.
Step 5: Made
SimpleMiniMax inherit from
MiniMax as well, then deleted out all methods from
SimpleMiniMax already implemented in
MiniMax, and add ed
@Override annotations to the methods which were implementing abstract methods.
Step 6: Re-ran the tests, which showed that I needed to change some of the methods from private to protected (so that methods in the super-class could be called from the sub-class), which solved the problem.
Step 7: Reviewed the two concrete classes and notices further duplication between the two classes, so used
Refactor > Pull members up to move the shared functionality up into
Step 8: Final re-run of the tests to make sure everything is working.
And that’s it. There were a few quirks, such as IntelliJ changing the order of the arguments to the class constructor. There were also some optimisations that I couldn’t work out how to do: in particular how to refer to the current sub-class to create a new instance of it in the parent class (which would avoid some code duplication). Overall though, I think this shows the power of IntelliJ in helping make refactoring easier.