SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

DAOパターンのデメリットを補う「DataAccessMethodパターン」

無駄なクラスを書くのが嫌になったあなたに送るコーディングTips

  • このエントリーをはてなブックマークに追加

DAOパターンは、企業向けシステム開発で利用される非常に優れたデザインパターンですが、多くのクラスやインターフェイスを定義する必要があるというデメリットがあります。そこで本稿では、GoFのTemplateMethodパターンをベースしたDataAccessMethodパターンを紹介します。これを用いると、通常のDAOパターンに比べてクラス数が激減します。

  • このエントリーをはてなブックマークに追加

はじめに

 CJ2EEのDataAccessObjectパターンは、企業向けシステム開発で利用される非常に優れたデザインパターンです。これを利用することにより、柔軟なシステムを構築することが可能となります。有名なパターンなので、多くの方はこのパターンを使った設計/開発に携わった経験があるのではないかと思います。

 しかし、DataAccessObjectパターンを使った開発は多くのクラスやインターフェイスを定義する必要があります。これは、DataAccessObjectパターンがAbstructFactoryパターンをベースとしているためです。クラスやインターフェイスの数が増えると開発コストだけでなく管理コストも増大し、開発規模が大きくなるほど影響が大きくなります。

 本稿では、こうしたDataAccessObjectパターンのデメリットを回避するためのパターンを紹介します。

対象読者

  • 企業システム開発に携わっている方
  • CJ2EEおよびGoFを理解されている方

DataAccessObjectパターン

 DataAccessObjectパターンでは、BusinessObjectからデリゲートされたデータアクセスの要求に対して、DataAccessObjectがデータアクセス処理を行いその結果を返します。DataAccessObjectはDBなどのデータアクセス処理を隠蔽(抽象化)するため、BusinessObjectはデータアクセス処理の方法を意識する必要がなくなります。また、開発工程ではスタブまたはMySQL、結合試験工程ではOracleを使うといったこともできるようになります。

 ところが、このDataAccessObjectパターンの導入には一つの問題があります。

 DataAccessObjectパターンは少なくとも1つのテーブルに対して1つのDataAccessObject(データアクセスオブジェクト)クラスを定義する必要があります。さらにBusinessObjectとDataAccessObjectの間の情報を交換するためにDataTransferObject(データ転送オブジェクト)クラスも定義しなければなりません。場合によってはビューやシーケンスに対しても定義しなければならないかもしれません。

 これだけで相当な数のクラスを定義したことになりますが、実は、これで最低レベルの話です。AbstructFactoryパターンをベースにしているということはAbstructFactory(抽象工場)クラスを定義するということです。さらに、DataAccessObjectやDataTransferObjectの抽象化を図るためのインターフェイスをクラスとは別に定義する必要もあります。

 DataAccessObjectパターンではこれだけのクラスやインターフェイスを開発しなければならないので、最近では自動生成ツールの採用が常識となっています。

 しかし、自動生成で定義されたDataAccessObjectはパフォーマンスが悪いと言われています。これはDataAccessObject自体のパフォーマンスが悪いというよりもDataAccessObjectの使用方法が最適ではないために発生することが多いのですが、DataAccessObjectはデータアクセス処理を隠蔽しているので、開発者にDataAccessObjectの最適な使用法を示すことが難しいのです。

 もちろん、DataAccessObjectパターンを導入すべきケースはあります。ただ、導入時にはパターンによるメリット・デメリットを洗い出し分析する必要があるのです。残念ながら、そうしたことをきちんと行ってから導入するというプロジェクトは多くありません。

データアクセス処理を分離するもう一つの方法

 さて、こうしたDataAccessObjectパターンのデメリットを挙げたところで、それに変わる方法が無ければ問題解決にはなりません。

 問題解決の糸口を探す前に、DataAccessObjectパターンのメリットをもう一度確認してみましょう。我々の注目しているDataAccessObjectパターンの最大のメリットは「業務処理とデータアクセス処理の分離」ではないでしょうか。

 データアクセス処理を分離したいのであれば、DataAccessObjectパターンを使う必要はありません。次の例を見てください。

データアクセス処理を分離するもう一つの方法
public class BusinessLogic {
    public void businesslogic(Request req) {
        ……
        ……
        empInfo = selectEmpInfo(id);
        ……
    }
    private EmpInfoDto selectEmpInfo(String id) {
        ……
        // 従業員情報テーブルからデータを検索
        ……
    }
}

 何か、ごく当たり前のコードに見えませんか?

 しかし、このコードはきちんと「データアクセス処理の分離」という責任を果たしています。つまり、わざわざEmpInfoAccessObjectのようなクラスを別に定義しなくても、データアクセス処理を分離することは可能なのです。

 確かに、このよく知られたこの方法では分離の強制という点では不十分かもしれません。コーディングガイドに上記のコードのように分離するように促しても、開発者はついついサボってしまうかもしれません。しかし、そういったことはコードインスペクションで回避できるのです。

DataAccessMethodパターン

 DataAccessObjectパターンを使わなくてもデータアクセス処理を分離できることは述べました。しかし、DataAccessObjectパターンにはもう一つのメリットがあります。それはデータアクセス処理を切り替えられることです。

 上記のコードでは、データアクセス層が分離されているとは言っても、DBMSの変更が発生すればクラスも修正しなければなりません。

 こういったことまで解決するには、privateメソッドとして分離したのではダメです。次のコードを見てください。

DBMSの変更に対応できるように修正
public class BusinessLogic {
    public void businesslogic(Request req) {
        ……
        ……
        empInfo = selectEmpInfo(id);
        ……
    }
    protected EmpInfoDto selectEmpInfo(String id) {
        ……
        // 従業員情報テーブルからデータを検索
        ……
    }
}

 何が変わったのでしょうか。

 実は、selectEmpInfoのスコープが単にprotetedに変わっただけです。しかし、これによって、MySQLからOracleに変更された場合でも、BusinessLogicを触ることなくselectEmpInfoをオーバーライドするだけで対応が可能となるのです。

 では、さらに一歩進んで修正してみましょう。

DBMSの変更に対応できるようにさらに修正
abstract public class BusinessLogic {
    public void businesslogic(Request req) {
        ……
        ……
        empInfo = selectEmpInfo(id);
        ……
    }
    abstract protected EmpInfoDto selectEmpInfo(String id);
}

 何が起こったのでしょうか?

 selectEmpInfoの中身であるデータアクセス処理の実装を消してしまったのです。具象メソッドを抽象メソッドにしてしまったのです。

 では、データアクセス処理の実装はどこに行ってしまったのでしょうか。

消えたデータアクセス処理の実装
public class BusinessLogicMySQL extends BusinessLogic {
    protected EmpInfoDto selectEmpInfo(String id) {
        ……
        // 従業員情報テーブルからデータを検索
        ……
    }
}

 消えたデータアクセス処理の実装は、サブクラスとして再定義されていたわけです。BusinessLogicを継承したBusinessLogicMySQLselectEmpInfoとして復帰しています。

 これはGoFのTemplateMethodパターンを応用したコードで、selectEmpInfoをhookメソッドと言います。hookメソッドでデータアクセス処理を行うようにコーディングすることで、DBMSが変更されても柔軟に対応することができます。

 この設計方式を、筆者はDataAccessMethodパターンと呼んでいます。

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
依存性の逆転

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

瑞瑞(ズィーズィー)

Java屋。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/349 2007/12/13 16:02

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング