2003年
前回、EJB Strategyパターンのクライアントからの問題点として
以下のようなものがありました。
1.メソッドの引数をEventオブジェクトにしなければならない。
2.その為、コンパイラの型チェックが利かない。
3.メソッド名がhandle〜の為、コードがわかりにくくなる。
今回はこれらを解決します。
その為に
”クライアントとStrategyServerDelegateとの間に、個別のクラスを
用意して、StrategyとEventをクライアントから隠蔽する。”
を行います。
それではソースを見てみましょう。前回から変更・追加したクラスのみ掲載します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
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を学ぶ理想的な道のり」について
考えてみたいと思います。
んじゃ
やまろう