Question

How I can modify this class to follow DIP (Dependency Inversion Principle) in order to remove the two ArrayList dependencies in the constructor? How should the interfaces be?

One thing that confuses me is that the new references points to an ArrayList<type> not just the constructor of a class. And I don't know how to handle that situation...

package mvc.controllers;

import java.util.ArrayList;
import mvc.models.AbstractModel;
import mvc.views.AbstractViewPanel;

public abstract class AbstractController {

    private ArrayList<AbstractViewPanel> registeredViews;
    private ArrayList<AbstractModel> registeredModels;

    public AbstractController() {
        registeredViews = new ArrayList<AbstractViewPanel>();
        registeredModels = new ArrayList<AbstractModel>();
    }

    public void addModel(AbstractModel model) {
        registeredModels.add(model);
        model.addPropertyChangeListener(this);
    }

    public void removeModel(AbstractModel model) {
        registeredModels.remove(model);
        model.removePropertyChangeListener(this);
    }

    public void addView(AbstractViewPanel view) {
        registeredViews.add(view);
    }

    public void removeView(AbstractViewPanel view) {
        registeredViews.remove(view);
    }
    ...
}
Was it helpful?

Solution

To do it in Dependency Inversion -way, you could do one of the following:

  1. Dependencies to the lists are given in the constructor:

    public abstract class AbstractController {
    
    private List<AbstractViewPanel> registeredViews;
    private List<AbstractModel> registeredModels;
    
    public AbstractController(List<AbstractViewPanel> registeredViews, List<AbstractModel> registeredModels) {
        this.registeredViews = registeredViews;
        this.registeredModels = registeredModels;
    }
    
  2. Add mutators (setters) for the lists:

    public abstract class AbstractController {
    
    private List<AbstractViewPanel> registeredViews;
    private List<AbstractModel> registeredModels;
    
    public AbstractController() {
    }
    
    public void setRegisteredViews(List<AbstractViewPanel> views) {
       this.registeredViews = views;
    }
    
    public void setRegisteredModels(List<AbstractModel> models) {
       this.registeredModels = models;
    }
    

Btw, I changed the ArrayLists to Lists. There's no need to introduce a dependency on the List implementation.

OTHER TIPS

It's not really clear what dependency you're trying to remove, but if you want to remove the explicit ArrayList instantiation, you could use constructor injection:

private final List<AbstractViewPanel> registeredViews;
private final List<AbstractModel> registeredModels;

public AbstractController(final List<AbstractViewPanel> registeredViews,
        final List<AbstractModel> registeredModels) {
    this.registeredViews = registeredViews;
    this.registeredModels= registeredModels;
}

I wouldn't inject a List into an object, and thus break encapsulation, just for the sake of unit testing it by mocking the list. The List is not an external dependency. It's part of the internals of the class.

If you want to unit-test this class, test that the method who uses the objects stored in the list do actually use them as they should. You should also test that the propertyChange method is called when you change a property of a model that you've added to the controller.

Or you could add a getView() and a getModels() method (potentially protected), to test that the addition worked as expected.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top