Java Refactor led to Circular Link

I have this kind of code in a desktop application

This is just a JPanel that contains buttons and such things.

class ApplicationPanel {

   private Listener listener;

   public ApplicationPanel(){
      this.listener = new Listener(this);
   }
}

This adds events to the controls in JPanel above.

class Listener {

   private ApplicationPanel panel;

   public Listener(ApplicationPanel panel){
      this.panel = panel;
   }
}

The caller code will be like this:

public void main(String[] args){
   ApplicationPanel panel = new ApplicationPanel();
}

If I try to apply dependency injection AND factories (will be changed later for Guice)

class ApplicationPanel {

   private Listener listener;

   public ApplicationPanel(){
      this(new Listener());
   }

   public ApplicationPanel(Listener listener){
      this.listener = listener;
   }
}

class Listener {

   private ApplicationPanel panel;

   public Listener(){
      this(new ApplicationPanel());
   }

   public Listener(ApplicationPanel panel){
      this.panel = panel;
   }
}

The caller’s code will be: As you can see, there is a circular dependency in this code What is the best way to solve this problem?

public void main(String[] args){
   Listener listener = new Listener(panel);
   ApplicationPanel panel = new ApplicationPanel(listener);

}
+3
source share
3 answers

; guice , , guice, , -, .

+3

: .

, ( ), .

+2

, unittest ApplicationPanel Listener, Listener ApplicationPanel ( Listener, , ApplicationPanel). mock Listener , , .

, Listener ApplicationPanel ApplicationPanel. . , Listener ApplicationPanel, , ApplicationPanel !

Instead, pass data to the listener when it receives events:

public interface Listener {

  void onApplicationChanged(ApplicationPanel panel){
  }
}

A more traditional way to add a listener to an object that dispatches events is to call a method:

public class ApplicationPanel {
  private List<Listener> listeners = new CopyOnWriteArrayList<Listener>();

  public void addListener(Listener listener) {
    listeners.add(listener);
  }
}

If you want a class that dispatches events to use the constructor to specify listeners, and you want to use Guice, check out Multibinder . ApplicationPanelwill look like this:

public class ApplicationPanel {
  private Set<Listener> listeners;

  @Inject
  public ApplicationPanel(Set<Listener> listeners) {
    listeners = new HashSet<Listener>(listeners);
  }
}
+2
source

Source: https://habr.com/ru/post/1773626/


All Articles