便利なコードパーツ集!

やまろうのプログラミングTips

Java

EJB Strategyパターン ~ クライアントからStrategyを隠蔽する。

投稿日:2016年12月6日 更新日:

2003年
前回、EJB Strategyパターンのクライアントからの問題点として
以下のようなものがありました。
1.メソッドの引数をEventオブジェクトにしなければならない。
2.その為、コンパイラの型チェックが利かない。
3.メソッド名がhandle〜の為、コードがわかりにくくなる。
今回はこれらを解決します。

その為に
”クライアントとStrategyServerDelegateとの間に、個別のクラスを
用意して、StrategyとEventをクライアントから隠蔽する。”
を行います。
それではソースを見てみましょう。前回から変更・追加したクラスのみ掲載します。

package sample;

import ejbstrategy.StrategyServerDelegate;
import ejbstrategy.Event;

/**
 * クライアントとStrategyServerDelegateとを仲介して
 * StrategyとEventをクライアントから隠蔽する。
 */
public class SampleService {
  private StrategyServerDelegate delegate;

  public SampleService() {
    this.delegate = new StrategyServerDelegate();
    SampleStrategy stategy = new SampleStrategy();
    this.delegate.setStrategy(stategy);
  }

  /**
   * 顧客データを取得する。
   * @param customerCd
   * @return 顧客データ
   */
  public String getCustomerData(String customerCd) {
    Event event = new Event();
    event.setData(customerCd);
    event.setName("getCustomerData");
    try {
      return (String)this.delegate.handleSupports(event);
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }

  /**
   * 注文データを取得する。
   * @param customerCd
   * @param orderDate
   * @return 注文データ
   */
  public OrderVO[] getOrderDatas(String customerCd, String orderDate) {
    OrderVO data = new OrderVO();
    data.setCustomerCd(customerCd);
    data.setOrderNo(orderDate);

    Event event = new Event();
    event.setData(data);
    event.setName("getOrderData");
    try {
      return (OrderVO[])this.delegate.handleSupports(event);
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }

  /**
   * 注文データを更新する。
   * @param customerCd
   * @param orderDate
   */
  public void updateOrderData(String customerCd, String orderDate) {
    OrderVO data = new OrderVO();
    data.setCustomerCd(customerCd);
    data.setOrderNo(orderDate);

    Event event = new Event();
    event.setData(data);
    event.setName("updateOrderData");
    try {
      this.delegate.handleRequired(event);
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }
}

package sample;

import ejbstrategy.*;

/**
 * パターン説明の為のサンプルStrategy
 */
public class SampleStrategy extends EJBStrategyAdapter {
  public Object handleRequired(Event event) {
    //DBの注文データを更新する等の処理をする。サンプルなので適当な値を返す
    Object result = "executed updateOrderData";
    return result;
  }

  public Object handleSupports(Event event) {
    Object result = null;
    String eventName = event.getName();
    if (eventName.equals("getCustomerData")) {
      //DBから顧客データを読み込む等の処理をする。サンプルなので適当な値を返す
      result = "executed getCustomerData";
    } else if (eventName.equals("getOrderData")) {
      //DBから注文データを読み込む等の処理をする。サンプルなので適当な値を返す
      OrderVO[] array = new OrderVO[20];
      array[0] = new OrderVO();
      array[0].setOrderNo("001");
      result = array;
    }
    return result;
  }

}

package sample;

import java.io.*;

/**
 * 注文情報を格納するオブジェクト
 */
public class OrderVO implements Serializable {
  private String customerCd;
  private String orderDate;
  private String orderNo;
  public String getCustomerCd() {
    return customerCd;
  }
  public void setCustomerCd(String customerCd) {
    this.customerCd = customerCd;
  }
  public String getOrderDate() {
    return orderDate;
  }
  public void setOrderDate(String orderDate) {
    this.orderDate = orderDate;
  }
  public String getOrderNo() {
    return orderNo;
  }
  public void setOrderNo(String orderNo) {
    this.orderNo = orderNo;
  }
}

package sample;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import ejbstrategy.*;

/**
 * パターン説明の為のサンプルServlet
 */
public class SampleServlet extends HttpServlet {
  private static final String CONTENT_TYPE = "text/html; charset=Shift_JIS";
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    Object result1 = null;
    Object result2 = null;
    try {
      //利用する側からはEJBStrategyパターンを意識させなくなった。
      //Eventオブジェクトを使わず、普通のメソッド呼び出しになっている。
      SampleService service = new SampleService();                    //(1)
      result1 = service.getCustomerData("00405");                     //(2)
      OrderVO[] array = service.getOrderDatas("00405", "20030903");
      result2 = array[0].getOrderNo();

      service.updateOrderData("00405", "20030903");
    } catch (Exception ex) {
      throw new ServletException(ex);
    }
    response.setContentType(CONTENT_TYPE);
    PrintWriter out = response.getWriter();
    out.println("<html>");
    out.println("<head><title>SampleServlet</title></head>");
    out.println("<body bgcolor=\"#ffffff\">");
    out.println("result1=" + result1);
    out.println("result2=" + result2);
    out.println("</body></html>");
  }
}

SampleServiceクラスを見てみましょう。
コンストラクタでStrategyServerDelegateを生成してSampleStrategy
をセットしてフィールドに保持しています。
そして、 public OrderVO[] getOrderDatas(String customerCd, String orderDate)
等のわかりやすいメソッド名 & シグニチャのpublicメソッドを提供しています。

クライアントはSampleServiceクラスを生成して、publicメソッドを呼び出すだけで
良いのです。EventやStrategyオブジェクト等を扱うことはありません。
それをSampleServletのコードで確認できます。
(1)でSampleServiceクラスを生成して、
(2)でpublicメソッドを呼び出しています。通常のJavaクラスを扱うのと同じです。

これにより、クライアントのコードがとてもわかりやすくシンプルになりました。
前回のSampleServletと見比べてみてください。

それでは最後に、普通にEJBを開発する場合とのクラス構成を比べてみます。
[普通にEJBを開発する場合]

1.EJB本体
2.リモートインターフェース
3.ホームインターフェース
4.Business Delegate
5.ejb-jar.xml

[EJB StrategyパターンでEJBを開発する場合]

1.EJB本体(StrategyServerBeanを使用する)
2.リモートインターフェース(StrategyServerを使用する)
3.ホームインターフェース(StrategyServerHomeを使用する)
4.Business Delegate(StrategyServerDelegateを使用する)
5.ejb-jar.xml(StrategyServerEJB用のDDを使用する)

以下が新規に作成が必要
6.EJBStrategyインターフェースを実装、またはEJBStrategyAdapterクラスを
継承したクラス(SampleStrategyのようなクラス)
7.StrategyServerDelegateを隠蔽するラップクラス(SampleServiceのようなクラス)

普通にEJBを開発する場合、1〜5を開発しなければならないですが、
EJB StrategyパターンでEJBを開発する場合、6・7を開発するだけで済むと
いうわけです。

開発するクラスの数は減るわけですが、普通にEJBを開発する場合に比べ
クラス構成が複雑になってしまうというのが、残念な所です。
しかし、6のクラスは普通Javaクラスなので、テストするのが容易で
あるというメリットがあります。6のクラスにビジネスロジックを記述するので
EJBとしてデプロイしなくとも、JUnit等でビジネスロジックを十分にテスト
することが可能です。バグが見つかっても、コードを修正してコンパイル
するだけで、テストを繰り返すことが出来ます。これは生産性において
とても大きなメリットをもたらします。

いかがだったでしょうか?欠点は抱えていながらも、大きな可能性を持って
いそうな気がします。もう少し改良や、昨日の限定をすれば、きっと大きな
メリットをもたらすのではないでしょうか?

とはいえ、EJBを開発して経験のない人にとっては、ピンとこなくて、退屈
だったかもしれません。私の説明も足りなくて分りにくかったかも知れません。
次回は軽い話題にしようということで、「Javaを学ぶ理想的な道のり」について
考えてみたいと思います。

んじゃ
やまろう

スポンサーリンク

-Java

Copyright© やまろうのプログラミングTips , 2022 AllRights Reserved Powered by AFFINGER4.