labs / tiddlers / content / labs / lab03 / _Labs_03_Refactoring the DAO

The DAO fields are currently hard-coded to a specific DAO instance, which is being initialized in the dialog classes. If we want to switch from using one DAO to another we need to update the fields in all of our GUI classes.

In this section we will refactor the system to allow us to pass the DAO objects into the dialogs rather that have the dialogs responsible for creating them. This is known as inversion of control --- the control of the dependency (the DAO objects in this case) is taken away from the user of the dependency (the dialogs) and is instead injected into the user via some mechanism (we will be passing the dependency to the dialogs via the constructor).

Another benefit of dependency injection (which is what this specific form of inversion of control is called) is that it makes the system easier to test. We can now supply mock DAO objects to the GUI classes in order to test that the GUI classes are interacting with the DAO objects correctly. We will make use of this in the lab next week.

We will refactor the system so that a single DAO object is created in the App class, and is passed through to the dialogs via the constructors. We need to pass it to the MainMenu frame, which will in turn pass it to the dialogs.

  1. Open the StudentEditor dialog.

  2. Locate the dao field. Note the following:

    • This field is using the StudentDAO interface type on the left hand side. This is important since we will be basing our mock DAO on the StudentDAO interface.

    • The field is final. This will help to ensure that the only object that is stored in this field is the one that will be passed into the constructor. Final fields can only be initialised at the point that they are declared, or via a constructor.

  3. Remove the field initialisation. Delete the right hand side of the declaration including the = character.

  4. Modify the constructor so that it takes an instance of the StudentDAO interface as a parameter.

    Use this parameter to initialise your DAO field. The initialisation should go before any code in the constructor that uses the DAO.

  5. You might notice some compiler errors appear in the other GUI classes --- we will fix those soon so ignore them for the meantime.

  6. Open the MainMenu frame. Add a StudentDAO field to the top of the class. Leave the field uninitialised. Make the field private final as done in the StudentEditor.

  7. Add a parameter to the MainMenu constructor just like you did in the StudentEditor dialog that initialises the DAO field.

  8. Fix the compiler error in the In the btnAddActionPerformed button handler by passing the new DAO field into the constructor call for the StudentEditor dialog. This is the handler that is called when the user clicks the <

    > button on the main menu.

  9. Open the App class. Fix the compiler error in this class by creating a DAO instance. It does not need to be a field --- just create a variable inside the main method:

    StudentDAO dao = new StudentCollectionsDAO();
  10. Pass the new dao instance into the MainMenu constructor.

  11. Complete the same process for the StudentViewer dialog.

  12. Fix any other errors relating to the DAO fields. You might need to move the initialisation of some fields into the constructor after the DAO field is initialised.

    You will also need to pass the DAO into the StudentViewer dialog when it is created in the MainMenu.

  13. Test the system by running it. You should see that it behaves as it used to.

So what have we achieved with this refactoring?

  • There is now one place that we need to modify (the App class) if we want to change the type of DAO that is being used. Previously there were only two places, but that is only because our system is quite simple and only requires two dialogs. If there were ten dialogs there would be ten places that we would have needed to change.

  • We can now pass different types of DAO objects into our GUI classes for different purposes. For example, when we want to test the GUI classes we can pass mock DAO objects that can be used to verify that the GUIs are interacting with the DAO objects correctly.