Wicket通用组件设计模式

时间:2011-12-14 05:34:37

标签: java generics design-patterns wicket wicket-1.5

我实现了一些通用组件,我只是想知道我的设计模式是否有意义,以及是否可以进行任何改进。例如,这是一个可用于过滤内容的通用面板:

/**
 * Abstract class for textfields used for filtering. When overriding abstract method onUpdateFilter, the first thing
 * that must be done is to set the paramsobject, or else filtering wont work.
 * @author fred
 *
 */

public abstract class FilterFormPanel extends Panel {

    private static final long serialVersionUID = 1L;
    private FilterForm filterForm;
    private Object paramsObject; //this is object because paramsobjects differ depending on entity type

    public FilterFormPanel(String id) {
        super(id);
        filterForm = new FilterForm("filterForm");
        add(filterForm);
    }

        public String getFilterString(){
        return filterForm.getFilterString();
    }

    public void setParamsObject(Object paramsObject){
        this.paramsObject = paramsObject;
    }

    /**
     *For developers to implement in class that contains the correct references to params and facade objects, dataviews etc.
     *e.g. they could do params.setFilter(<reference to an instance of this class>.getFilterString() and ajax stuff too) 
     */
    public abstract void onUpdateFilter(AjaxRequestTarget target, Object paramsObject);

    private class FilterForm extends Form<Void> {

        private static final long serialVersionUID = 1L;
        private transient String filterString;

        public FilterForm(String id) {
            super(id);
            final TextField<String> filterTextField = new TextField<String>("filterTextField", new PropertyModel<String>(this, "filterString")); //textField for user to enter filter string
            add(filterTextField);

            add(new AjaxButton("filterButton") { //button to click for performing overriden method
                private static final long serialVersionUID = 1L;
                @Override
                protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                    onUpdateFilter(target, paramsObject);
                }
            }); 
        }

        public String getFilterString(){
            return filterString;
        }   
    }
}

在另一个类中使用如下:

    filterFormPanel = new FilterFormPanel("filterFormPanel"){

        private static final long serialVersionUID = 1L;

        @Override
        public void onUpdateFilter(AjaxRequestTarget target, Object paramsObject) {
            filterFormPanel.setParamsObject(params);
            params.setFilterString(filterFormPanel.getFilterString());
            //ajax stuff
            target.addComponent(dataViewContainer);
            nav.setVisible(dataProvider.size()!=0);
            target.addComponent(nav);
            emptyLabel.setVisible(dataProvider.size()==0);
            target.addComponent(emptyLabel);
        }

    };

    settingsContainer.add(filterFormPanel);

当一个人重写方法时,首先要强制使用setParamsObject方法,这是令人讨厌的。有没有更好的方法来实现对该对象的引用?这是否是在wicket中实现可重用和相对通用组件的通用方法?任何反馈都会非常感激,我相信这里还有改进的余地。

编辑I:仅仅针对某些情况,我正在做的是实现像这样的页面

enter image description here

我向用户显示数据视图和过滤选项。有许多不同实体的页面,但GUI组件可以而且应该尽可能通用,以免违反DRY。示例代码显然是页面的过滤器文本字段和按钮部分。

编辑II:我希望这个组件在可能的情况下更加松散耦合,例如使它能够做完全不同的事情,而不仅仅是修改一个params对象(例如,有另一种情况,我需要更新两个params对象,然后我将无法使用此面板)。现在需要对覆盖方法中要使用的对象的引用的形式中的onSubmit方法是已知的。有没有办法不这样做或动态设置这些对象的存在和/或类型?

编辑III:重点是这个面板的核心功能实际上只是让用户

  • 输入字符串
  • 当用户点击按钮时,通知并将该字符串的访问权限授予系统的其他部分。

“系统的其他部分”对字符串的作用不应该与此面板有关,但就像现在一样,它与params对象耦合,“系统的另一部分”必须在该对象上执行一些操作。如果可能的话,我想摆脱这种耦合。我不妨想使用此面板中的字符串来打印到控制台或将其用于其他任意任务。

3 个答案:

答案 0 :(得分:3)

您可以使用类的构造函数来设置对象。

如果让paramsObject使用Java Generics(因此名称:)),将采用更通用的方法。您可以超类化实体或让它们实现接口。

答案 1 :(得分:2)

我在使用Wicket的Web应用程序上工作了3年多(现在在1.4.x下开始使用1.3.x并计划在几周内升级到1.5.x)。您使用的方法是我们在内部使用的方法。我们经常使用抽象类来表示常见的面板。我们唯一做的就是rotsch在他的回答中说,我们使用了很多泛型来尽可能地推断类型参数。

答案 2 :(得分:0)

实际上,即使我最初没有意识到这一点,只需这样做就可以轻松实现:

/**
 * Abstract class for textfields used for filtering.
 * @author fred
 *
 */

public abstract class FilterStringPanel extends Panel {

private static final long serialVersionUID = 1L;
private FilterForm filterForm;

public FilterStringPanel(String id) {
    super(id);
    filterForm = new FilterForm("filterForm");
    add(filterForm);
}

public String getFilterString(){
    return filterForm.getFilterString();
}

/**
 *For developers to implement in class that contains the correct references to params and facade objects, dataviews etc.
 *e.g. they could do params.setFilter(<reference to an instance of this class>.getFilterString() and ajax stuff too) 
 */
public abstract void onUpdateFilter(AjaxRequestTarget target);

private class FilterForm extends Form<Void> {

    private static final long serialVersionUID = 1L;
    private transient String filterString;

    public FilterForm(String id) {
        super(id);
        final TextField<String> filterTextField = new TextField<String>("filterTextField", new PropertyModel<String>(this, "filterString")); //textField for user to enter filter string
        add(filterTextField);

        add(new AjaxButton("filterButton") { //button to click for performing overriden method
            private static final long serialVersionUID = 1L;
            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                onUpdateFilter(target);
            }
        }); 
    }

    public String getFilterString(){
        return filterString;
    }   
}
}

然后以这种方式实施:

    settingsContainer.add(new FilterStringPanel("filterStringPanel"){
        private static final long serialVersionUID = 1L;
        @Override
        public void onUpdateFilter(AjaxRequestTarget target) {
            params.setFilterString(getFilterString());
            target.addComponent(dataViewContainer);
            nav.setVisible(dataProvider.size()!=0);
            target.addComponent(nav);
            emptyLabel.setVisible(dataProvider.size()==0);
            target.addComponent(emptyLabel);
        }
    });

这样我们就不需要发送任何对象的引用(例如需要用AJAX进行更新的params对象或wicket组件),我们可以重用这个面板用于我们想要的任何内容!