Wicket + lambdas:タイプセーフで簡潔なIModel実装

Webアプリケーションの開発における標準タスク:データオブジェクトがあり、このデータを表示する必要があります(HTMLで出力)。 Apache Wicketでは 、このデータはモデル( IModelインターフェイスの実装)を使用して(表示に関与する)コンポーネントにバインドされます。



ほとんどの場合、この出版物は既に知識を持っている人によって読まれますが、念のために: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; } }
      
      









試み1:私たちは書いた、私たちは書いた...



タスクのソリューションにアプローチする方法は次のとおりです。



 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の匿名サブクラスを作成します。 すぐに動作し、明らかに見えます。 1つの問題は、同じ匿名クラスを使用するとコードが面倒になることです。コンポーネントあたり6行は冗談ではありません。



試行2:脚の方向に撃つ



PropertyModelを試してください:



 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は長い間リリースされており、 ラムダメソッドリファレンスは急いで助けになりました。



 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は魔法なしで実装されます:2つのファクトリメソッド(ofModel()およびofObject())を追加しました。



参照資料



  1. Apacheウィケットフレームワーク
  2. Java:ラムダ式
  3. Java:メソッド参照



All Articles