|
to Top
Behaviorについて記述します。
// ======================================================================================================
// Behavior
// ========
★★★★★★★★★★★★★★★★★★★★★★
新デザインへの移行がまだできておりません。
申し訳ありませんが、しばらくお待ち下さい。
★★★★★★★★★★★★★★★★★★★★★★
# ----------------------------------------------------------
# What is behavior?
# -----------------
Behaviorとは
「DaoとEntityの定番処理を行うObject」
名前の由来は? → Daoの振舞い (The behavior of dao)
その役割は? → Data-HandlingのFacade (The facade of data handling)
S2DaoのDaoは実質的にSQLの実行しかできませんが、実際の業務アプリでは、
“整合性Check”や“Paging処理”などのDataを扱った定番処理を行わなければなりません。
それらの定番処理をDBFluteで自動生成したものがBehaviorとなります。
他のO/R-Mapperで似た位置付けを挙げるならば、
「Hibernateで言うDao」、「Torqueで言うPeer」に相当します。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
厳密な意味がどうでもいい人は、
「DBFluteではBehaviorを使って検索したり更新したりする」と覚えてもらうだけで構いません。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# ----------------------------------------------------------
# The merit of behavior
# ---------------------
先に挙げた“Paging処理”を例にとって比較します。
Paging処理は一般的に以下のような処理になります。
1. Paging条件無しの時の全件Record数の検索 → select count(*) from xxx
2. Paging条件ありでの検索 → select ... from xxx limit 20 offset 40
3. {1}と{2}の結果から総Page数や次Page存在判定などの計算
こういった処理の再利用を解決します。
{Behaviorを利用しない}
呼び出し側が{1}-{2}-{3}の処理を手続き的に行います。
Daoを使って{1}と{2}を実行し、{3}の処理を呼び出し側が自分で行います。
その辺の処理の再利用を自分で考える必要があります。
ex) BOOK一覧のPaging検索
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
final BookDao bookDao = [...DaoのInstanceを取得]
final BookCB cb = new BookCB();
[...ConditionBean(条件)の設定]
cb.fetchFirst(20); // 1PageのSizeは20件
cb.fetchFirst(3); // 3Page目を検索したい
final int allRecordCount = bookDao.selectCount(cb); // {1}の処理を実行
final java.util.List<Book> bookList = bookDao.selectList(cb); // {2}の処理を実行
[...結果から計算] // {3}の処理を実行 ※ここが大変(Bugも生みやすい)
// Paging結果のHandling
[...Pagingの結果情報がバラバラなので必要に応じて独自のDTOにまとめる] // ※ここも面倒である
- - - - - - - - - -/
{Behaviorを利用する}
{1}-{2}-{3}の処理を自動生成された一行のMethod呼び出しで完了します。
こういったApplication依存でない「DaoとEntityの定番処理」の再利用が既に解決されています。
ex) BOOK一覧のPaging検索 -- selectPage()
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
final BookBhv bookBhv = [...BehaviorのInstanceを取得]
final BookCB cb = new BookCB();
[...ConditionBean(条件)の設定]
cb.fetchFirst(20); // 1PageのSizeは20件
cb.fetchFirst(3); // 3Page目を検索したい
final PagingResultBean<Book> bookPage = bookBhv.selectPage(cb); // {1}-{2}-{3}の処理を実行
// Paging結果のHandling
[...単一ObjectのbookPageからPaging結果に関する全ての情報が取得できる]
- - - - - - - - - -/
また、BehaviorもEntityやDaoと同様にGenerationGapになっているため、Application独自の処理を
実装することも可能です。該当のTableが持つ固有のLogic(Dataの振舞い)をBehaviorに実装し、
複数のProcess(画面やBatchなど)で利用するLogicの再利用を解決することが可能です。
# ----------------------------------------------------------
# How to use behavior
# -------------------
Behaviorは、dbflute.diconにてInterfaceを持たないClassとしてComponent登録されます。
Interfaceを持たないため、Setter-Injectionされるか否かはS2ContainerのVersionに依存します。
利用したいBehaviorのComponentNameと同名のSetterを用意すればInjectionされます。
/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public class Xxx {
public void setBookBhv(BookBhv bookBhv) {
this.bookBhv = bookBhv;
}
public void executeXxx() {
final Book entity = Book();
entity.setBookId(123);
entity.setBookName("xxx");
this.bookBhv.insertOrUpdate(entity);
}
}
- - - - - - - - /
# ----------------------------------------------------------
# What kind of methods does behavior have?
# ----------------------------------------
Behaviorの用途別Method概要 をご覧下さい。
# ---------------------------------------------------------
# The other merit of behavior
# ---------------------------
BehaviorはS2Daoの“クセ”を隠蔽します。
冒頭で挙げた“整合性Check”というのがそれに該当します。
【ParameterのCheck】
Parameterに対する整合性Checkを掛けることができます。
{Behaviorを利用しない}
S2DaoのDaoは、Interfaceのみが存在していて、Methodが呼び出された後の処理に対して
Applicationで手を加えることが一切できません。(やるとなったらInterceptorになってしまう)
なので、ParameterのNullCheckなど呼び出し側が随時やる必要があります。
{Behaviorを利用する}
Behaviorで自動生成されたMethodは引数の厳密なCheckとDebug用Messageを格納した例外発生を行います。
呼び出し側がMethod呼び出し前にCheckしたり、Debugしづらい例外が発生してしまうことはありません。
【戻り値の整合性Check】
1件を期待しているのに複数件HITしてしまった場合の扱いが違います。
{Behaviorを利用しない}
S2DaoのDaoの“戻り値がEntity型の1件検索Method(selectEntity())”は、
S2Daoの仕様として「SQLが複数件数を返してきた場合は最初の1件を返す」となっています。
実開発においては、「例外にして欲しい」と思うところです。
(1件を期待しているのに複数件だったら既に条件かDataかどこかにBUGあるため)
{Behaviorを利用する}
1件を期待しているのに複数件だったら専用の例外になります。
もし最初の1件を検索したい場合は、Paging機能で先頭の1件だけを指定して検索すれば実現できます。
ex) BOOKの1件検索 -- selectEntity()
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
final BookBhv bookBhv = [...BehaviorのInstanceを取得]
final BookCB cb = new BookCB();
[...ConditionBean(条件)の設定]
final Book book = bookBhv.selectEntity(cb); // NullCheckが行われる。
- - - - - - - - - -/
また、既に絶対1件HITすることが前提の検索Methodが存在します。
{Behaviorを利用しない}
また、S2DaoのDaoの“戻り値がEntity型の1件検索Method(selectEntity())”は0件HIT時にnullを返します。
実開発においては、「既に絶対1件HITすることが前提」で検索することがかなり多いです。
そのとき、呼び出し側がいちいち戻り値をNullCheckするのは面倒ですし、Checkせずに
Data不備でnullが帰ってきて、NullPointerExceptionが発生するのも効率が悪いです。
{Behaviorを利用する}
0件取得時にDebug用Messageを格納した例外発生を行います。
ex) BOOKの1件検索 -- selectEntityWithDeletedCheck()
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
final BookBhv bookBhv = [...BehaviorのInstanceを取得]
final BookCB cb = new BookCB();
[...ConditionBean(条件)の設定]
final Book book = bookBhv.selectEntityWithDeletedCheck(cb); // 戻り値のNullCheckが行われる。
assertNotNull(book); // bookがnullになることは絶対にない
- - - - - - - - - -/
これらはちょっとした実装補助ではありますが、10人20人と開発者が増えれば増えるほど効果を発揮します。
「このちょっとした実装補助が無いためにDebugに時間を掛けてしまった」なんてことは避けたいと考えます。
(呼び出し側はBehaviorのみ利用し、S2DaoのDaoを直接参照しないことを推奨)
|