PoEAA ch9 Table Module

PoEAAデザインパターン勉強メモ

出典: 


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を生やす、ということに意味がない