Я пытаюсь использовать диспетчера события, чтобы позволить модели уведомлять подписанных слушателей, когда она изменяется. диспетчер события получает класс обработчика и имя метода для вызова во время отправки. предъявитель подписывается на образцовые изменения, и обеспечьте реализацию Обработчика, которую назовут на изменениях.
Вот код (я сожалею, что это немного длинно).
EventDispacther:
package utils;
public class EventDispatcher<T> {
List<T> listeners;
private String methodName;
public EventDispatcher(String methodName) {
listeners = new ArrayList<T>();
this.methodName = methodName;
}
public void add(T listener) {
listeners.add(listener);
}
public void dispatch() {
for (T listener : listeners) {
try {
Method method = listener.getClass().getMethod(methodName);
method.invoke(listener);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
Модель:
package model;
public class Model {
private EventDispatcher<ModelChangedHandler> dispatcher;
public Model() {
dispatcher = new EventDispatcher<ModelChangedHandler>("modelChanged");
}
public void whenModelChange(ModelChangedHandler handler) {
dispatcher.add(handler);
}
public void change() {
dispatcher.dispatch();
}
}
ModelChangedHandler:
package model;
public interface ModelChangedHandler {
void modelChanged();
}
Предъявитель:
package presenter;
public class Presenter {
private final Model model;
public Presenter(Model model) {
this.model = model;
this.model.whenModelChange(new ModelChangedHandler() {
@Override
public void modelChanged() {
System.out.println("model changed");
}
});
}
}
Основной:
package main;
public class Main {
public static void main(String[] args) {
Model model = new Model();
Presenter presenter = new Presenter(model);
model.change();
}
}
Теперь, я ожидаю добираться, "модель изменила" сообщение. Однако я получаю java.lang. IllegalAccessException: Класс utils. EventDispatcher не может получить доступ к члену предъявителя класса. 1 Presenter$ с модификаторами "общественность".
Я понимаю, что класс для обвинения является анонимным классом, который я создал в предъявителе, однако я не знаю, как больше делать его 'общественностью', чем это в настоящее время. Если я заменяю его именованным вложенным классом, это, кажется, работает. Это также работает, если Предъявитель и EventDispatcher находятся в том же пакете, но я не могу признать что (несколько предъявителей в различных пакетах должны использовать EventDispatcher),
какие-либо идеи?
Это ошибка JVM ( ошибка 4819108 )
Временное решение - вызвать method.setAccessible ( true)
перед вызовом метода method.invoke (listener)
Я предполагаю, что анонимный класс всегда частный
, но я не нашел четкого заявления об этом в Спецификации языка Java (я смотрел в §15.9.5)
В Java , если тип недоступен, его члены тоже.
Если вам нравится черная магия, вы можете отключить проверку доступа с помощью method.setAccessible (true)
. В качестве альтернативы вы можете потребовать, чтобы ваши обработчики событий назывались классами или рассматриваемый метод был объявлен в доступных типах.
В таком случае использовать отражение - действительно плохая идея. Просто позвольте диспетчеру вызвать требуемый метод. Если вам нужно несколько диспетчеров для вызова разных методов, просто подклассифицируйте их.
В Java отсутствуют закрытия, но помощь уже в пути!