Java Refactoring FAQ: Can you provide an example of the Extract Interface refactoring process?
While working on a Java Swing development project recently, I had written a couple of controllers (as in controllers from the Model/View/Controller pattern), and I was about to write some more, when I realized that if I refactored my Java source code I would have a much better design -- source code I code more easily maintain.
The pattern I saw repeated in my Java controller classes was that they all had similar method names, something like this:
- doAddAction
- doEditAction
- doViewAction
- doDeleteAction
- doSearchAction
As I realized I was repeating this same pattern over and over again, I realized that I really needed to do one of two things: Either (a) pull all of these methods up into a common base class, or (b) extract all of these methods into an interface.
While I can't get into all of the reasoning behind my decision to use the Extract Interface refactoring pattern here, I will give you two points of information that will help you decide how to approach this problem when you run into it. The first consideration is "What is the difference between a Java Interface and a Java class, such as an abstract base class?"
Differences between a Java Interface and abstract class
The primary differences between a Java interface and an abstract Java class are:
- One is an Interface, which is implemented by other classes.
- The other is an abstract class, which can be extended by other Java classes.
- The abstract class allows you to specify default behavior for your Java methods.
- Very importantly, a Java class can implement multiple Java Interfaces, but can extend only one Java class.
To understand the rest of the reason why I choose to use the "Extract Interface" refactoring here would require a discussion of Design Patterns in Java, and I don't want to get into all of that today. Instead, I'd rather look at the mechanics of the Extract Interface refactoring process.
A Java Extract Interface refactoring example
My refactoring example is fairly simple. I had a number of controller classes that looked like this:
public class ProcessController { public void doAddAction() { // stuff here ... } public void doEditAction() { // stuff here ... } public void doViewAction() { // stuff here ... } public void doDeleteAction() { // stuff here ... } public void doSearchAction() { // stuff here ... } } public class EntityController { public void doAddAction() { // stuff here ... } public void doEditAction() { // stuff here ... } public void doViewAction() { // stuff here ... } public void doDeleteAction() { // stuff here ... } public void doSearchAction() { // stuff here ... } }
Once I saw this pattern repeated in my source code several times, I took a few moments to think about which Design Pattern was the most appropriate for my situation, and based on that decision, I decided to use the Extract Interface refactoring method.
Step 1: The first step in that process was to create a Java Interface that looks like this:
public interface ControllerInterface { public void doAddAction(); public void doEditAction(); public void doViewAction(); public void doDeleteAction(); public void doSearchAction(); }
Step 2: The next step in this process was to have all of my controller classes implement this interface, like this:
public class ProcessController implements ControllerInterface { // same code as before ... } public class EntityController implements ControllerInterface { // same code as before ... }
Step 3: While those two steps are the basic part of the Extract Interface refactoring method, the next step was really the hard work, and unfortunately too long and detailed to discuss thoroughly here. In short, here's what I did:
I changed my main controller class to define its controllers like this:
// changed to make these references of "ControllerInterface" type ControllerInterface processController = new ProcessController(); ControllerInterface entityController = new EntityController();
Next, I did some other magic in this class so all it knew was that it was dealing with a ControllerInterface; this class would no longer know that it was dealing with a ProcessController, an EntityController, a FooController, or any other controller. The class only knew it had references to a collection of ControllerInterface objects, and a ControllerInterface can do those five things shown above.
Summary
I know this Java Extract Interface refactoring example isn't complete, but you'll have to trust me that it would take a great deal of time to complete it. As mentioned before, please look at my Java Design Pattern tutorials for more information on this decision making process.
Also, I mentioned the Model/View/Controller (MVC) pattern above, and here are some good links to MVC tutorials: