[Seasar][Teeda][DBFlute]S2Dxoを使わない選択肢

https://www.seasar.org/svn/sandbox/dbflute/trunk/dbflute-example/src/main/java/org/seasar/dbflute/example/approot/web/mainte/book/SearchPage.java

上記のTeeda + DBFluteのサンプルを見て驚いた。なるほどぉ、こういうDxoを使わないやり方もあったのか!
実に学ぶことが多い。素晴らしいサンプルコードです。


【ポイント1】ForeachにDtoのリストではなく、Entityのリストを用いている

わざわざForeach用にDtoを作成しなくてもいいのが嬉しい。

  private List<Book> resultItems;


【ポイント2】S2Dxoを使わずにForeachを実現している

ポイントは currentメソッドですね。一般的なTeedaのForeachの処理としては、フレームワーク側がSetter経由でフィールドにセットした現在行の列の値をGetter経由で読み取ります。一方、この方式では、このcurrentメソッドのおかげで、Foreach用の各Getterメソッドの内部で現在行のEntityを取得できるようになります。各Getterメソッド内でDxoに相当する処理の一部を記述するという訳です。この方法の隠れた利点として、Foreach用のGetterさえ用意すれば、フィールドやSetterを用意しなくても済むということがあげられます。

    protected Book current() {
        if (resultItems != null && !resultItems.isEmpty()) {
            return (Book) resultItems.get(resultIndex);
        }
        String msg = "The resultItems had no item so DON'T invoke this method!";
        throw new IllegalStateException(msg);
    }

    public String getBookId() {
        return current().getBookId().toString();
    }

    public String getBookName() {
        return current().getBookName();
    }

    public String getIsbn() {
        return current().getIsbn();
    }


【ポイント3】NotNullでない関連エンティティのNull対策をif文を使わずに実現している
下記の例では、getAuthorメソッドの代わりにtraceAuthorメソッドを用いている。traceAuthorメソッドはgetAuthorメソッドと異なり、authorがnullの場合には空のエンティティを返します。これによって、getAuthorNameメソッドの呼び出し時に NullPointerExceptionが発生しません。つまり、Null対策のためにif文を使った分岐処理を書かなくても済んでしまいます。

    public String getAuthorName() {
        return current().traceAuthor().getAuthorName();
    }


publicフィールドの導入やPage間で重複する処理をAbstractの親Pageに移動することで、さらにコード記述量も減るので、わざわざActionとPageを分離しなくても良いと思う。


追記:
TeedaでForeachを実現するためには、Entityのリストではなく、わざわざ専用のDtoのリストを用意して、さらにDtoの中身と同じアクセッサをPageに用意する方法が一般的です。今はこの方法に、すっかり慣れてしまいました。しかし、Teedaを触り始めた時は、この方法はDRY原則にも反していることもあって少し違和感を感じていました。


でも、今回のDxoを用いない方法ならば、DxoDtoを作成する必要がないだけでなく、Pageクラスの繰り返し用のフィールドやそのSetterメソッドの記述を不要にし、単なるアクセッサではない、意味のあるGetterをスマートに書くことができる。コード量も少なくなり、可読性も向上する。これならば、これからTeedaを触る人でも、私が触り始めた頃に感じたForeachの違和感を感じることは無いように思えます。


しかし、現段階では、検討が不十分だが、今回のやり方は、参照系のPageでしか有効にならないと思う。PageクラスからEntityクラスに変換する必要のある更新系の処理にはDxoを使う方が楽だと思う。(他にも、まだ、試していないが、プルダウンなどの選択項目用に共通コンポーネントとして LabelValueDxo のようなものを作っておくのは有効かも。)


いずれにせよ、あまりフレームワークの設計者が考慮していなかった(?)と思われるところから、利用者側から画期的な活用方法が生まれるのは面白い。