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を開発する場合]
2.リモートインターフェース
3.ホームインターフェース
4.Business Delegate
5.ejb-jar.xml
[EJB StrategyパターンでEJBを開発する場合]
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を学ぶ理想的な道のり」について
考えてみたいと思います。
んじゃ
やまろう