【问题标题】:Wicket hacked use of ListView, which alternatives?Wicket hacked 使用 ListView,有哪些替代方案?
【发布时间】:2018-01-11 03:03:00
【问题描述】:

检票口使用模型可能很麻烦。要使有状态页面正确呈现对象,您需要使用大量样板代码、重写类以正确获取可见性状态等......一个简单的例子:

private IModel<FooBar> fooBarModel;
public MyPage() {
    Label lbl1 = new Label("field1",
               new PropertyModel<>(fooBarModel, "field1")) {
        @Override public boolean isVisible() {
             return fooBarModel.getObject().someCondition();
    }   }
    add(lbl1);
    /// Etc... same for dozen of other fields
}

我经常使用ListView 来提供帮助。同样的例子:

public MyPage() {
    add(new ListView<FooBar>("content",
                new SingleListModel<FooBar>(fooBarModel)) {
        @Override protected void populateItem(...) {
            FooBar fooBar = item.getModelObject();
            // Code here gets simpler:
            Label lbl1 = new Label("field1", fooBar.getField1());
            lbl1.setVisible(fooBar.someCondition());
            item.add(lbl1);
            // Etc...
        }
    });
}

使用简单的实用程序类SingleListModel,将IModel&lt;T&gt; 转换为ListModel&lt;T&gt;,具有1 个或0 个元素,具体取决于T 是否为空:

public class SingleListModel<T>
extends LoadableDetachableModel<List<T>> {
    private IModel<T> tModel;
    public SingleListModel(IModel<T> tModel) {
        this.tModel = tModel;
    }
    @Override
    protected List<T> load() {
        List<T> ret = new ArrayList<>(1);
        T t = tModel.getObject();
        if (t != null)
            ret.add(tModel.getObject());
        return ret;
    }
}

这样做的好处是,如果fooBarModel 返回null,标记中的整个“内容”元素将被隐藏;无需特殊处理。

但这一切对我来说都像是一种黑客行为,因为我以某种“不自然”的方式使用 ListView。

有没有更简洁的方法来获得相同的结果?标准检票口框架?

【问题讨论】:

  • 我投票结束这个问题,因为关于工作代码的问题属于Code Review。
  • @Michael 我不这么认为。它看起来对我来说是合法的。
  • @soorapadman “有什么好的方法来做 X?”是基于意见的。
  • 我并不是真的在问“做 X 的好方法”,而是“比 X 更干净的方法”,X 是一个 hack。

标签: java frameworks wicket


【解决方案1】:

您应该使用 Behavior 来避免此类重复。

public class MyBehavior extends Behavior {

   private final MyModel model;

   public MyBehavior(MyModel model) {this.model = model;}

   @Override public void onConfigure(Component c) {
      if (model.someCondition()) {
        component.setVisible(false);
      }
   }
}

用法:

MyBehavior b = new MyBehavior(modelInstance);
component1.add(b);
component2.add(b);
// dozen more

【讨论】:

  • 感谢这个有用的提示。但在这里,我的问题实际上与代码重复无关。我有许多具有许多不同可见性条件的不同对象和字段,因此这需要许多不同的行为来控制可见性。使用 ListView 的诀窍是能够使用诸如 setVisible(cond) 和 new Label("x", fooBar.getX()) 之类的代码创建视图,而无需创建十几个模型/行为/子类。这种 ListView 的使用在 Wicket 中有更清晰的模式吗?
【解决方案2】:
Label lbl1 = new Label("field1",
           new PropertyModel<>(fooBarModel, "field1")) {
    @Override public boolean isVisible() {
         return fooBarModel.getObject().someCondition();
}   }
add(lbl1);

几乎不需要重构就可以转换成

add(new FLabel("id","text")
        .setVisibilityFunction(()->model.getObject().isVisible()))
);

FLabel 类:

public class FLabel extends Label implements IComponentWithVisibilityFunction<FLabel> {

    private SerializableBooleanSupplier visibilityFunction;

    public FLabel(String id) {
        super(id);
    }

    public FLabel(String id, Serializable label) {
        super(id, label);
    }

    public FLabel(String id, IModel<?> model) {
        super(id, model);
    }

    @Override
    public FLabel setVisibilityFunction(SerializableBooleanSupplier visibilityFunction) {
        this.visibilityFunction = visibilityFunction;
        return this;
    }

    @Override
    protected void onConfigure() {
        if (visibilityFunction != null) {
            setVisible(visibilityFunction.getAsBoolean());
        }
    }
}

public interface IComponentWithVisibilityFunction<T> {
    T setVisibilityFunction(SerializableBooleanSupplier visibilityFunction);
}

此外,您可以将供应商放入构造函数中:

add(new FLabel("id","text", ()->model.getObject().isVisible()));

【讨论】:

  • 感谢所有这些答案,但这并不能真正回答我的问题。我“被黑”使用 ListView 的最初目的是在页面渲染时推迟各种子组件的创建,而不是在页面构建期间。这种方法的优点是它可以防止使用许多 lambda / 匿名类,并且可能更有效。我更想问是否有一个标准的组件/方法来做同样的事情,而不是使用 ListView。
猜你喜欢
  • 2011-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-25
  • 2010-09-07
  • 1970-01-01
相关资源
最近更新 更多