观察员/事件听众
public class LocaleChangeEvent extends EventObject {Locale locale;public LocaleChangeEvent(Object source, Locale locale) {super(source);this.locale = locale;}public Locale getLocale() {return locale;}
}
其次,我们需要一个接口LocaleChangeListener。
public interface LocaleChangeListener extends EventListener {void processLocaleChange(LocaleChangeEvent event);
}
@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 listenersLocaleChangeEvent lce = new LocaleChangeEvent(this, this.selectedLocale);for (LocaleChangeListener lcl : localeChangeListeners) {lcl.processLocaleChange(lce);}}...
}
@ManagedBean
@SessionScoped
public MyBean implements LocaleChangeListener, Serializable {// UserSettingsForm can be injected e.g. via @ManagedProperty annotation or via Spring facilityprivate UserSettingsForm userSettingsForm;@PostConstructpublic void initialize() {userSettingsForm.addLocaleChangeListener(this);}public void processLocaleChange(LocaleChangeEvent event) {// reset something related to I18N data...}
}
就观察者模式而言,UserSettingsForm是可观察的,而LocaleChangeListener的实例(如MyBean)则是观察者。 讨论的模式带有一些您需要注意的重要问题。 豆紧密耦合。 有很多手动工作来重新注册bean。 Bean必须实现定义的接口。 如果您有100个语义不同的更改通知了bean,则它必须实现100个接口。 无法通知已注册的侦听器的子集–即使不需要通知所有侦听器,也总是会通知他们。 最后但并非最不重要的– 内存管理问题 。 马丁·福勒(Martin Fowler)写道: “假设我们有一些观察某些域对象的屏幕。 关闭屏幕后,我们希望将其删除,但是域对象实际上通过观察者关系携带了对屏幕的引用。 在内存管理的环境中,寿命长的域对象可能会占据很多僵尸屏幕,从而导致大量内存泄漏。”
调解员
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 facilityreturn 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);}
}
public MyBean implements MediatorListener, InitializingBean, Serializable {public void afterPropertiesSet() throws Exception {...Mediator.getCurrentInstance().addCollaborator(this);}@Overridepublic void listenToEvent(MediatorEvent event) {if (event instanceof LocaleChangeEvent) {// do something}}
}
public class LocaleChangeEvent implements MediatorEvent {...
}public class UserSettingsForm implements Serializable {private Locale selectedLocale;private List<SelectItem> locales;public void localChangeListener(ValueChangeEvent e) {...// notify listenersMediator.getCurrentInstance().fireEvent(new LocaleChangeEvent(this, this.selectedLocale));}...
}
参考: JSF中基于事件的通信。 我们的JCG合作伙伴 Oleg Varaksin在“ 软件开发思想”博客上的过时做法 。
翻译自: https://www.javacodegeeks.com/2012/07/jsf-event-based-communication-old.html