Проблема в том, что вы не можете выполнить юнит-тест ApplicationPanel
с фальшивкой Listener
, потому что Listener
принимает ApplicationPanel
(если вы используете конструктор по умолчанию для Listener
, тогда у слушателя будет поле, ссылающееся на вещественное ApplicationPanel
).Вы можете использовать макет Listener
с фреймворком, но в этом случае я думаю, что циклические зависимости могут указывать на запах кода.
Реальная проблема с этой циклической зависимостью заключается в том, что Listener
получает ссылкудо ApplicationPanel
до завершения строительства ApplicationPanel
.Это может вызвать проблемы безопасности потока.Даже если путь к коду не является многопоточным, Listener
может вызвать ApplicationPanel
, который вызывает отправку события, до того, как ApplicationPanel
инициализирует список прослушивателей!
Вместо этого передайте данные слушателю, когда он получает события:
public interface Listener {
void onApplicationChanged(ApplicationPanel panel){
}
}
Более традиционный способ добавить слушателя к объекту, отправляющему события, - вызвать метод:
public class ApplicationPanel {
private List<Listener> listeners = new CopyOnWriteArrayList<Listener>();
public void addListener(Listener listener) {
listeners.add(listener);
}
}
Если вы хотите, чтобы класс, отправляющий события, использовал конструктор для указания слушателей, и вы хотите использовать Guice, посмотрите на Multibinder .ApplicationPanel
будет выглядеть так:
public class ApplicationPanel {
private Set<Listener> listeners;
@Inject
public ApplicationPanel(Set<Listener> listeners) {
listeners = new HashSet<Listener>(listeners);
}
}