連載
» 2005年06月08日 00時00分 公開

JavaのDBアクセスを極める(5):デザインパターンを利用したDBアクセスの実装 (3/3)

[林田宏介 著, 安間裕 監修,アクセンチュア・テクノロジー・ソリューションズ]
前のページへ 1|2|3       

レイヤ間の依存を少なくするための実装

 Facadeパターンを利用することで、ビジネスロジックとデータベース・アクセスの各レイヤの責任範囲を明確化することができました。しかし、ただ分離しただけではFacadeクラスとDAOクラスの間に強い依存が残ってしまい、DAOクラス自体に変更があった場合などにその影響をFacadeクラスにも与えてしまいます。

 これを回避するには、各レイヤ間の結合度を低くする必要があるということを第2回「O/Rマッピングで失敗しない分析・設計のポイント」で解説しましたが、具体的な実装ではFactoryパターンにDAOパターンを組み合わせた「Factory for Data Access Objects Strategy」を利用します。

 組み合わされるFactoryパターンには「インスタンス生成をサブクラスに任せるFactory Methodパターン」と「依存し合うオブジェクト群を具象クラスを明確にせずに生成させるAbstract Factoryパターン」の2つのケースがありますが、今回はデータベース製品の変更やO/Rマッピングツール(パーシステンス・フレームワーク)への変更などを考慮して、Abstract Factoryパターンを組み合わせています。Factory for Data Access Objects Strategyを利用したクラスの構成は以下のようになります。

図5 Factory for Data Access Objects Strategyクラス図(Abstract Factory)(画面をクリックすると拡大します) 図5 Factory for Data Access Objects Strategyクラス図(Abstract Factory)(画面をクリックすると拡大します)

 Factory for Data Access Objects Strategyはパターンごとに、「DAOインスタンスの生成」と「永続化処理の実装」の2つから成り立っていますので、それぞれの処理ごとに解説していきます。

DAOインスタンスの生成

 まずDAOインスタンスの生成について、前項で解説したOrderFacade.javaのインスタンス生成部分の流れに沿って解説します。

DAOFactory dao =
      DAOFactory.getDAOFactory(DAOFactory.ORACLE); // (1)
ShoppingcartDAO sdao = dao.getShoppingcartDAO();   // 
OrderDAO odao = dao.getOrderDAO();                 // (2)
Order_detailDAO oddao = dao.getOrder_detailDAO();  // 
リスト4 OrderFacade.javaのDAOインスタンス生成部分

 インスタンス生成の処理では、最初にDAOインスタンス生成クラスであるDAOFactoryクラスのインスタンスを生成しています(リスト4の(1))。この処理ではDAOFactoryクラスのgetDAOFactoryメソッドに属性を渡して、属性ごとにFactoryクラスの実体クラスであるConcreteFactoryクラスを返します(リスト5)。

 このケースではOracle属性を渡していますので、OracleDAOFactoryクラスのインスタンスを取得しています。こうすることでデータベースの変更があった場合に、属性の切り替えのみで業務クラスを修正せずに対応できるようになり、実装上の問題として提起した「データベース変更時に広範囲の修正が必要」を回避することが可能となります。

 次に、取得したDAOFactoryクラスから実際に永続化処理を行いたいDAOの実体クラスを取得しています(リスト4の(2))。OracleDAOFactoryクラスでは、それぞれDAOの実体を提供するアクセサメソッドを実装しているので、呼び出されたメソッドごとにDAOインスタンスを生成して返します(リスト6)。例えば、getShoppingcartDAO()を呼び出した場合には、ショッピングカート・テーブルにアクセスするためのDAOの実体であるConcreteDAOクラスのOracleShoppingcartDAOクラスのインスタンスを取得できます。

public abstract class DAOFactory {
  public static final int ORACLE = 1;   //Oracle属性定義
  public static final int DB2    = 2;   //DB2属性定義
  public abstract ShoppingcartDAO getShoppingcartDAO()
        throws PersistenceException;
  public abstract OrderDAO getOrderDAO()
        throws PersistenceException;
  public abstract Order_detailDAO getOrder_detailDAO()
        throws PersistenceException;
  public static DAOFactory getDAOFactory(int SelectFactory) {
    switch (SelectFactory) {
      case ORACLE :
           //属性ごとのConcreteFactory
          return new OracleDAOFactory();
      case DB2    :
          return new DB2DAOFactory();
      default     :
          return null;
    }
  }
}
リスト5 DAOFactory.java
public class OracleDAOFactory extends DAOFactory {
  public ShoppingcartDAO getShoppingcartDAO()
        throws PersistenceException{
    return new OracleShoppingcartDAO();
  }
  public OrderDAO getOrderDAO() throws PersistenceException{
    return new OracleOrderDAO();
  }
  public Order_detailDAO getOrder_detailDAO()
        throws PersistenceException{
    return new OracleOrder_detailDAO();
  }
}
リスト6 OracleDAOFactory.java

永続化処理の実装

 次に永続化処理の実装についてですが、これはOrderFacade.javaの実装部分(リスト7)を見れば分かるとおり、単純にインスタンス生成処理で取得したConcreteDAOクラスのメソッドを呼び出すだけになります。

tm.begin();                         //トランザクションの開始
ShoppingDTO sdto =                  //ショッピングカート
  sdao.findShoppingCart(cart_id);   //データの取得
odao.setUserId(sdto.getUserId());   //発注テーブルの
                                    //更新データのセット
odao.insertOrder();                 //発注テーブルの更新
sdto.setHachuId(odao.getHachuId()); //発注IDセット
oddao.insertOrder_detail(sdto);     //発注明細テーブルの更新
リスト7 OrderFacade.javaの永続化処理実装部分

 ただし、ConcreteDAOクラスへ自由にアクセスできるようにすると、ビジネスロジック側でもデータベース・アクセスに依存した処理を行えるようになるため、ビジネスロジック側にはインターフェイスのみを提供するようにします。インスタンス生成処理でConcreteDAOクラスを生成する部分を見てください。ConcreteDAOクラスの取得時には、直接ConcreteDAOクラスのインスタンスを生成するのではなく、インターフェイスクラスのインスタンスとして生成しています。これによりビジネスロジック側はインターフェイスとして提供されている機能のみ利用することができ、それ以外はカプセル化によりデータベース・アクセスを意識せずに実装可能となります。

 例えば、O/Rマッピングツール(パーシステンス・フレームワーク)へ変更する場合などに、ConcreteDAOクラスのみを変更し、ほかのクラスには修正をかけずに対応することが可能となります。また、実装上の問題として提起した「ビジネスロジック上でのデータ変換処理の多発」を回避するために、ConcreteDAOクラスではデータの属性変換も実装しデータベースへの依存をここで吸収しています。

発注明細テーブルに処理を行うクラス

 それでは実際に発注明細テーブルに処理を行うOrder_detailDAOの実装を見てみましょう。Order_detailDAOクラス自体はインターフェイスクラスですので実装は持たず、インターフェイスとしてビジネスロジック側へ提供するメソッドだけを持っています。実際に実装を持っているのは、Order_detailDAOクラスの実装クラスであるOracleOrder_detailDAOクラスになります。OracleOrder_detailDAOクラスはOrder_detailDAOで定義されたメソッドを実装し、ビジネスロジック側から呼ばれたときにそれぞれの処理を行います。また、ConcreteDAOクラスではトランザクション制御を上位のFacadeクラスに任せるため、データベース・コネクションのOpen処理は行いますが、Close処理については上位クラスで行われるため、Closeを行うメソッドのみを提供します。

public interface Order_detailDAO {
  public Order_detailDTO findOrder_detail(
       
String hachu_id, String shohin_code);
  public int insertOrder_detail(ShoppingcartDAO dto);
  public boolean updateOrder_detail(ShoppingcartDAO dto);
  public void close() throws PersistenceException;
  // 中略
}
リスト8 Order_detailDAO.java
public class OracleOrder_detailDAO
        implements Order_detailDAO  {
  private static final String DATA_SOURCE_NAME =
        "Java:comp/env/jdbc/SampleDatabase";
  private Connection con = null;
  public OracleOrder_detailDAO()
        throws PersistenceException {
    DataSource ds = null;
    try {
      // DataSourceの取得は環境により異なります
      InitialContext ctx = new InitialContext();
      Object obj = ctx.lookup(DATA_SOURCE_NAME);
      ds = (DataSource) PortableRemoteObject
              .narrow(obj, DataSource.class);
      con = ds.getConnection();
    } catch (Exception ex) {
      throw new PersistenceException(
            "Order_detailDAO failure:" + ex.getMessage());
    } 
  }
  public void close() throws PersistenceException{
    try{
      if (con != null){
        con.close();
      }
    } catch (Exception ex){
      throw new PersistenceException(
            "close failure:" + ex.getMessage() );
    }
  }
  public Order_detailDTO findOrder_detail(……){}
  public int insertOrder_detail(……){}
  public boolean updateOrder_detail(……){}
  //中略
}
リスト9 OracleOrder_detailDAO.java

Point

  • Abstract Factoryパターンの適用により、ConcreteFactoryクラスの生成を属性で変えられるようにし、データベースの変更時の修正の影響範囲を抑える。
  • DAOパターンの適用により、データベース・アクセスに依存する操作をビジネスロジックから切り離すことができる。
  • ConcreteDAOクラス内でデータ属性の変換を行い、ビジネスロジック側へのデータベース依存ロジックを回避する。
  • トランザクション制御は上位クラスで行うため、ConcreteDAOクラスではコネクションの生成は行うがCloseに関してはメソッドのみ提供する。

まとめ

 今回はオブジェクト指向言語のJavaから、データモデルにミスマッチがあるリレーショナル・データベースへアクセスする際、実装時の影響を最小化するための解決策を解説しました。次回は永続化の処理でパフォーマンスを向上させるための実装について解説します。(次回に続く)

筆者紹介

アクセンチュア・テクノロジー・ソリューションズ

アクセンチュアから生まれた、企業改革のためのシステム開発を手掛けるエンジニア集団。安間裕が代表取締役社長を務める。諏訪勇紀はJavaに精通しSI上流での分析/設計を得意とするシニア・システム・アナリスト。



前のページへ 1|2|3       

Copyright© 2018 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。