使用@Dependent实现观察者模式

时间:2015-10-17 20:52:05

标签: jsf jsf-2 primefaces observer-pattern

当我继续研究我的JSF项目时,我已经达到了需要一些帮助才能让我更进一步的目标。

首先,我的整个项目都可以通过以下链接获得:https://github.com/vasigorc/rimmaproject它可以编译并运行。

总之,我有一个预约页面。到目前为止,约会的唯一领域是约会。它通过primefaces日历组件输入。支持会话约会bean实现了一个Observable接口(Observer设计模式的一部分)。只要日期值发生变化,就会通知观察者。观察者是依赖 bean,它调用REST客户端以获取所选日期的天气预报的对象表示。选择日期并且最终用户点击提交后,天气预报应显示在同一页面的右侧。

测试完成:我已对所有部分采集方法以及Observer和Observable实现之间的集成进行了单元测试。但是当我运行应用程序时,更改日期并单击“提交”日期不会出现。

我找不到描述相同问题的stackoverflow票证,但我找到了一篇IBM文章,描述了如何在JSF中实现不同的设计模式。他们的建议是使用事件监听器方法。在我的应用程序设计中掉头之前,我希望得到你的建议,试图找到我的应用程序现在构建方式的缺陷。

代码 前端 预约页面:

<div class="col-md-4">
        <h:form>     
            <h:panelGrid columns="2">
                <span>#{copy.pickadate}</span>
                <p:calendar id="calendar" value="#{appointmentFormBean.selectedDate}" locale="fr"
                            mindate="today" maxdate="today+90" mode="popup"
                            pattern="yyyy-MM-dd">                
                </p:calendar>
                <input id="requestButton" type="button" value="#{copy.submitButton}">
                    <f:ajax event="click" execute="calendar" render="out weatherwidget"></f:ajax>
                </input>                
            </h:panelGrid>
        </h:form>    
    </div>
    <div class="col-md-4 col-md-offset-4">
        <ui:include id="weatherwidget" src="restservice/weatherWidget.xhtml"/>
    </div>
    <div><h:outputText id="out" value="#{appointmentFormBean.selectedDate}"></h:outputText></div>

'天气小工具'

 <ui:composition>        
        <h:panelGrid columns="3" class="table table-bordered">
            <h:outputText rendered="#{appointmentFormBean.datePickerActivated}">#{forecastBeanTwo.forecast.day}</h:outputText>
        </h:panelGrid>            
</ui:composition>

约会支持bean的签名:

@Named(value = "appointmentFormBean")
@SessionScoped
public class AppointmentFormBean implements Serializable, Observed

负责调用Observer的方法

public void setSelectedDate(Date selectedDate) {
    this.selectedDate = selectedDate;
    notifyVGObservers();
    setDatePickerActivated(true);
}
@Override
public void notifyVGObservers() {
    observers.stream().map((observer1) -> (VGObserver) observer1).forEach((observer) -> {
        observer.update(selectedDate);
    });
}

'Observer'Bean的签名和托管属性声明:

@ManagedBean
@Dependent
public class WeatherForecastBean implements Serializable, VGObserver
@ManagedProperty(value = "#{appointmentFormBean}")
private AppointmentFormBean formBean;

注意观察点

//point of IoC
public void setFormBean(AppointmentFormBean formBean) {
    this.formBean = formBean;
    formBean.registerVGObserver(this);
}

最后,更新方法:

Override
public void update(Date selectedDate) {
    /*
        get the 15 days from today date object
        and check whether the client requested day is not 
        after it.
    */
    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.DATE, +15); 
    if (selectedDate.after(cal.getTime())) {
        /*
            So, if the selected date is after today+15 days
            then we will tell the client that we cannot grab a weathe for him
            i.e. DailyForecast = UnavailableForecast.class
        */
        setForecast(new UnavailableForecast());
    }else{
        /*
            Now that we know that the selected date is within the range
            of available forecasts, we need to extract the requested day 
            forecast (represented by a Time object) 
            from the total of 16 available days
        */
        java.sql.Date sqlDate = utilToSql(selectedDate);   
        Time requestedTime = findGoodTime(dwr.getDays(), 
                (Time t)->sqlDate.toString().equals(t.getDay()));
        setForecast(new TimeAdapter(requestedTime));
    }        
}

这不是一个简单的问题。正如我所说,完整的代码可以在github上找到,但是也欢迎您提出任何问题。任何建议都会有所帮助。

1 个答案:

答案 0 :(得分:0)

我放弃了我的旧设计,因为我需要继续推进该项目。我放弃了Observer-Observable对象关系,并且采用了IBM文章之前提到的路径:

  

观察者模式   Observer模式的目的是在主题中的状态发生变化时自动通知所有依赖对象(或观察者)。 JSF框架在UI组件中实现Observer模式。 JSF技术有两种内置事件:ActionEvent和ValueChangedEvent。 ActionEvent在确定用户界面组件(如按钮)的激活时非常有用。当用户单击该按钮时,JSF实现会通知添加到该按钮的一个或多个动作侦听器。按钮被激活或按钮(主体)的状态发生变化。所有监听器(或观察者)都会收到添加到按钮的主题状态变化的通知。同样,当输入UI组件中的值发生更改时,JSF实现会通知ValueChangeListeners。

来源:http://www.ibm.com/developerworks/library/wa-dsgnpatjsf/

这些是我所做的改变。

在前端我添加了PrimeFaces eventListener

<p:calendar id="calendar" value="#{appointmentFormBean.selectedDate}" locale="fr"
                            mindate="today" maxdate="today+90" mode="popup"
                            pattern="yyyy-MM-dd">    
                    <p:ajax event="dateSelect" listener="#{forecastBeanTwo.handleDateSelect}"/>
                </p:calendar>

在后端,我使用handleDateSelect()方法更改了update()方法:

public void handleDateSelect(SelectEvent event){
    /*
        get the 15 days from today date object
        and check whether the client requested day is not 
        after it.
    */
    Date selectedDate= (Date)event.getObject();
    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.DATE, +15); 
    if (selectedDate.after(cal.getTime())) {
        /*
            So, if the selected date is after today+15 days
            then we will tell the client that we cannot grab a weathe for him
            i.e. DailyForecast = UnavailableForecast.class
        */
        setForecast(new UnavailableForecast());
    }else{
        /*
            Now that we know that the selected date is within the range
            of available forecasts, we need to extract the requested day 
            forecast (represented by a Time object) 
            from the total of 16 available days
        */
        java.sql.Date sqlDate = utilToSql(selectedDate);   
        Time requestedTime = findGoodTime(dwr.getDays(), 
                (Time t)->sqlDate.toString().equals(t.getDay()));
        setForecast(new TimeAdapter(requestedTime));
    }  
    setBeanActivated(true);
}

然而一切正常......令我沮丧的是,因为这种设计看起来像是一种解决方法。