A single instance that handles the business logic for all rows in a database table or view.
Table Module
- OOのキーの一つ: データと振る舞いとをひとまとめにする
-
伝統的なOOにおけるオブジェクト
- アイデンティティをもつ
- 1オブジェクトは1つの個に対応する
- メソッドは1つの個に対する操作
- Domain Modelが立脚するのはこれ
-
Domain Modelの問題点
- 関連データベースとのインピーダンスミスマッチ
-
Table Module
-
ふるまい
- 1クラス1テーブル
-
データ
- 1オブジェクト1テーブル
- cf. Domain Modelは1オブジェクト1レコードとか
-
How It Works
-
つよみ
- データと振る舞いとのパッケージング
- RDBとの親和性
-
Table Moduleオブジェクトはアイデンティティをもたない
- orderテーブルを扱うなら、orderの集合に対応する
-
ので、メソッドを呼び出すときは毎回アイデンティティを指定する
- 主キーとか
-
Table Moduleを使うときはふつう、テーブル指向的なデータ構造が裏にある
- SQL問い合わせ結果をRecord Setとして保持したものとか
-
同一のRecord Setに複数のTable Moduleで操作を行うこともある
- theDatasetとする
-
対象は実表とは限らない
- クエリ結果
- ビュー
-
Table Moduleの実装をどうする
- インスタンス
-
静的メソッドの集合
- クラスは名前空間的なかんじになる
-
インスタンスがおすすめ
- theDataで初期化できる
- 継承できる
-
theDataをどうやってDBから取得する
-
Table Moduleのファクトリメソッドとして生やす
- 【補】テーブルごとに継承してoverrideする
-
Table Data Gatewayを別途用意する
-
デメリット
- 別途クラスを用意しなければならないこと
-
メリット
-
Table Moduleは1クラスで済ませらせる
- かわりにTable Data Gatewayをテーブルごとに用意する
-
DBと接続しないテスト用モックを用意することもできる
- メモリ上でRecord Setをでっち上げる
-
-
-
-
Table Moduleという名前
- 1実表1クラス感ある
- (ビューやクエリに対して作っても)ええんやで
When to Use It
-
Table Moduleはテーブル指向データに基づいている
- Record Setデータ構造がコードの中心となる
-
Table ModuleはOOの力をフルには発揮できない
- インスタンス-インスタンスの関連を表現できない
- ポリモーフィズムうまくいかない
-
複雑なドメインロジックの表現力と、テーブル指向的なデータ構造との親和性とはトレードオフ
- 前者: Domain Model
- 後者: Table Module
- Domain ModelとDBのテーブルとが似通っているなら、
Active Recordを使いDomain Modelを採用するとよい -
アプリケーションの他の部分(GUIフレームワークとか)がテーブル指向データに基づいてできているなら、
Table Module のほうが Domain Model + Active Record よりもうまくいく- .NETのADO: ActiveX Data Objectsとか
Example: Revenue Recognition (C#)
- テーブルからの読み出しは共通なので、基底TableModuleクラスに実装して、テーブル別TableModuleクラスで継承するなど
-
言語機構を上手に使うと捗る
-
例: C#のインデクサ
- 主キー等を添字に指定して、(連想)配列のごとくアクセスできる
-
class Contract...
public DataRow this [long key] {
get {
String filter = String.format("ID = {0}", key);
return table.Select(filter)[0];
}
}
-
カプセル化の話
-
何か追加の機能がある場合のみ行う
- コードの多重化を避けるため
-
public enum ProductType {WP, SS, DB};
class Product...
public ProductType GetProductType (long id) {
String typeCode = (String) this[id]["type"];
return (ProductType) Enum.Parse(typeof(ProductType), typeCode);
}
-
基本的にはカプセル化しない
- UIにテーブル指向データを食わせた場合、直接データアクセスされてしまうため
全部にsetter/getterを生やす、ということに意味がない
- UIにテーブル指向データを食わせた場合、直接データアクセスされてしまうため