Наблюдатель / Слушатель событий
01
02
03
04
05
06
07
08
09
10
11
12
13
|
public class LocaleChangeEvent extends EventObject { Locale locale; public LocaleChangeEvent(Object source, Locale locale) { super (source); this .locale = locale; } public Locale getLocale() { return locale; } } |
Во-вторых, нам нужен интерфейс LocaleChangeListener.
1
2
3
4
|
public interface LocaleChangeListener extends EventListener { void processLocaleChange(LocaleChangeEvent event); } |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@ManagedBean @SessionScoped public class UserSettingsForm implements Serializable { private Locale selectedLocale; private List<SelectItem> locales; private List<LocaleChangeListener> localeChangeListeners = new ArrayList<LocaleChangeListener>(); public void addLocaleChangeListener(LocaleChangeListener listener) { localeChangeListeners.add(listener); } public void localChangeListener(ValueChangeEvent e) { ... // notify listeners LocaleChangeEvent lce = new LocaleChangeEvent( this , this .selectedLocale); for (LocaleChangeListener lcl : localeChangeListeners) { lcl.processLocaleChange(lce); } } ... } |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
@ManagedBean @SessionScoped public MyBean implements LocaleChangeListener, Serializable { // UserSettingsForm can be injected e.g. via @ManagedProperty annotation or via Spring facility private UserSettingsForm userSettingsForm; @PostConstruct public void initialize() { userSettingsForm.addLocaleChangeListener( this ); } public void processLocaleChange(LocaleChangeEvent event) { // reset something related to I18N data ... } } |
С точки зрения шаблона Observer UserSettingsForm является Observable, а экземпляры LocaleChangeListener (например, MyBean) являются Observers. Обсуждаемый шаблон сопровождается некоторыми важными вопросами, о которых вам необходимо знать. Бобы тесно связаны. Есть много ручной работы, чтобы обработать бобы. Бины должны реализовывать определенные интерфейсы. Если ваш бин информирован о 100 различных семантических изменениях, он должен реализовать 100 интерфейсов. Невозможно уведомить подмножество зарегистрированных слушателей — всегда все слушатели получают уведомление, даже если они не нуждаются в уведомлении. Последнее, но не менее важное — проблема управления памятью . Мартин Фаулер написал: «Предположим, у нас есть несколько экранов, наблюдающих некоторые доменные объекты. Как только мы закрываем экран, мы хотим, чтобы он был удален, но доменные объекты на самом деле несут ссылку на экран через отношения наблюдателя. В среде с управлением памятью долгоживущие доменные объекты могут удерживать множество экранов зомби, что приводит к значительной утечке памяти ».
медиатор
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public interface MediatorEvent { ... } public interface MediatorListener { public void listenToEvent(MediatorEvent event); } public class Mediator implements Serializable { private Collection<MediatorListener> collaborators = new HashSet<MediatorListener>(); public static Mediator getCurrentInstance() { // access Mediator bean by JSF-Spring facility return ContextLoader.getCurrentWebApplicationContext().getBean( "mediator" ); } public void fireEvent(MediatorEvent event) { for (MediatorListener mediatorListener : collaborators) { mediatorListener.listenToEvent(event); } } public void addCollaborator(MediatorListener collaborator) { collaborators.add(collaborator); } public void removeCollaborator(MediatorListener collaborator) { collaborators.remove(collaborator); } } |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public MyBean implements MediatorListener, InitializingBean, Serializable { public void afterPropertiesSet() throws Exception { ... Mediator.getCurrentInstance().addCollaborator( this ); } @Override public void listenToEvent(MediatorEvent event) { if (event instanceof LocaleChangeEvent) { // do something } } } |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
public class LocaleChangeEvent implements MediatorEvent { ... } public class UserSettingsForm implements Serializable { private Locale selectedLocale; private List<SelectItem> locales; public void localChangeListener(ValueChangeEvent e) { ... // notify listeners Mediator.getCurrentInstance().fireEvent( new LocaleChangeEvent( this , this .selectedLocale)); } ... } |
Ссылка: Событийное общение в JSF. Олдскульный подход от нашего партнера JCG Олега Вараксина в блоге Мысли о разработке программного обеспечения .