- PVSM.RU - https://www.pvsm.ru -
Стандартная задача при разработке веб-приложения: есть объект данных, требуется эти данные отобразить (вывести в HTML). В Apache Wicket [1] данные для этого привязываются к компонентам (которые и будут заниматься отображением) с помощью моделей (реализующих интерфейс IModel [2]).
Вероятнее всего, эту публикацию будут читать те, кто уже в курсе, но на всякий случай: главный метод из IModel, который нас интересует, это:
T getObject();
Абстракция простая и лаконичная, но не всё так просто на практике. Под катом — сказ о том, как Java 8 помогла победить многословность и небезопасность стандартных подходов.
public class User implements Serializable {
private final String name;
private final int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
Вот как можно подойти к решению поставленной задачи:
public class AbstractReadOnlyModelPanel extends Panel {
public AbstractReadOnlyModelPanel(String id, IModel<User> model) {
super(id, model);
add(new Label("name", new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
return model.getObject().getName();
}
}));
add(new Label("age", new AbstractReadOnlyModel<Integer>() {
@Override
public Integer getObject() {
return model.getObject().getAge();
}
}));
}
}
Всё дёшево, надёжно и практично: создаём анонимный субкласс AbstractReadOnlyModel. Работает быстро, выглядит понятно. Одна проблема — из-за использования того самого анонимного класса код получается громоздкий: 6 строк на компонент — не шутка.
Теперь попробуем PropertyModel [3]:
public class PropertyModelPanel extends Panel {
public PropertyModelPanel(String id, IModel<User> model) {
super(id, model);
add(new Label("name", PropertyModel.of(model, "name")));
add(new Label("age", PropertyModel.of(model, "age")));
}
}
Ух ты, гораздо компактнее. Но в бочке мёда есть немало дёгтя:
К счастью, Java 8 уже давно выпущена, и лямбды [4] вместе с Method References [5] уже спешат на помощь:
public class GetterModel<E, P> extends AbstractReadOnlyModel<P> {
private final E entity;
private final IModel<E> entityModel;
private final IPropertyGetter<E, P> getter;
private GetterModel(E entity, IModel<E> entityModel, IPropertyGetter<E, P> getter) {
this.entity = entity;
this.entityModel = entityModel;
this.getter = getter;
}
public static <E, P> GetterModel<E, P> ofObject(E entity, IPropertyGetter<E, P> getter) {
Objects.requireNonNull(entity, "Entity cannot be null");
Objects.requireNonNull(getter, "Getter cannot be null");
return new GetterModel<>(entity, null, getter);
}
public static <E, P> GetterModel<E, P> ofModel(IModel<E> entityModel, IPropertyGetter<E, P> getter) {
Objects.requireNonNull(entityModel, "Entity model cannot be null");
Objects.requireNonNull(getter, "Getter cannot be null");
return new GetterModel<>(null, entityModel, getter);
}
@Override
public P getObject() {
return getter.getPropertyValue(getEntity());
}
private E getEntity() {
return entityModel != null ? entityModel.getObject() : entity;
}
}
public interface IPropertyGetter<E, P> {
P getPropertyValue(E entity);
}
Ну и сразу же пример, переписанный с этой реализацией модели:
public class GetterModelPanel extends Panel {
public GetterModelPanel(String id, IModel<User> model) {
super(id, model);
add(new Label("name", GetterModel.ofModel(model, User::getName)));
add(new Label("age", GetterModel.ofModel(model, User::getAge)));
}
}
Почти так же кратко, как и в примере с PropertyModel, к тому же:
По сравнению с PropertyModel, правда, есть и некоторые недостатки:
Зато есть приятный бонус: аналог магической возможности PropertyModel использовать в качестве источника данных и модели, и POJO реализуется без всякой магии: мы просто добавили два фабричных метода (ofModel() и ofObject()).
Автор: rpuch
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/75517
Ссылки в тексте:
[1] Apache Wicket: http://wicket.apache.org/
[2] IModel: https://wicket.apache.org/apidocs/1.4/org/apache/wicket/model/IModel.html
[3] PropertyModel: https://wicket.apache.org/apidocs/1.4/org/apache/wicket/model/PropertyModel.html
[4] лямбды: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
[5] Method References: https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
[6] Источник: http://habrahabr.ru/post/244211/
Нажмите здесь для печати.