Struts開発での考察

今更ながらStrutsでの開発の相談を受けたりするのですが、どうもStrutsは好きになれません。
自分が使うぶんにはいいのですが、他人が設計しているのを見ると、いつも同じところでつまづいています。
Actionの設計単位が明確に決まっていないために、破綻しているケースが多いです。

私が考える設計方針

Actionはイベント単位で設計する
画面遷移の単位でActionを定義しているために、つじつまが合わなくなったりするケースが多々見られます。
あくまでSubmit時に、Action(=行動)を呼び出し、そのイベントにあった処理を実行し、その結果として次の画面が得られると考えるべきだと思います。
Actionを画面遷移単位で考えると、同じ遷移だけどValidateをしたりしなかったりという矛盾が生じたりします。
でも、私の業務を考えると、大抵の場合はHTMLでの紙芝居的なモックアップを作るところから、外部設計が行われます。それをベースに考えると、画面遷移単位でActionを作るのが作りやすいのは確かです。(その対策については後述の振り分けActionを参照)
ActionFormはフォームデータの入れ物
ActionFormはFormのデータを入れる器と考えます。
Formのデータというのは、テキストボックスや、チェックボックスや、hidden項目です。あくまでこれらの器として使うべきで、Actionの実行結果をJSPに渡すのは、別のBeanを用意すべきだと思います。いわゆるDTO(Data Transfer Object)とか、VO(Value Object)と言われるものです。検索条件をActionFormに持って、検索結果はDTOに格納してJSPにrequest.setAttributeで渡すべきだと思います。
そうなると得てして、ActionFormの中身をDTOに移し替える処理が発生しますが、これはいたし方ないと思います。BeanUtilsで中身をコピーしてしまいます。
JSPでは、そのままでもActionFormを参照できるので無駄なような気がしますが、そうしないとページがActionFormに強く結びついてしまいます。それはつまりActionに依存しがちになるため、ページがActionに依存してきてしまい。他のActionから同じページを使いにくくなります。
ActionFormをnewするケース
前の項目とかぶりますが、次画面用のActionFormをnewしてそこに値を埋め込むこともあると思います。Actionで次画面用のデータを作成して、DTOに格納するわけですが、次画面のFormデータに関しては、そのActionFormをnewしてそちらで渡したほうがよいと思います。
これはStrutsのhtmlカスタムタグを使うにはその方が都合がよいからです。「ActionFormは入力フォームのデータ」だという概念があれば、次画面のActionFormをnewして渡すことには違和感はないかと思います。
Actionの連鎖を使う
action-forwardでの遷移先はJSPに限らず、Actionも定義できるので登録実行後に、再度検索を行うという処理は、登録Actionの遷移先が検索Actionという定義にすればOKです。
これをせずに登録Actionの後処理で次画面の検索処理を行うというのは、せっかくstruts-configにそういった連鎖の定義できるのを無駄にして、コード上に記述してしまっていることになります。
こういう書き方をしている人は、おそらくstruts-configの存在意義が分からず、定型的な記述になっていて、「なんのためにstruts-configがあるのだろうか?」と疑問をもっているかもしれません。
別Actionとして定義し、その関連をstruts-configに書くことで、struts-configを見れば、処理の連鎖になっているのかが分かります。

以上のように設計することで、非常にすっきりと迷うことなくActionを定義したり、ロジックを記述することができるようになりました。

1つ問題点は、イベント単位でアクションを設計することです。外部設計時には、画面遷移が重視されて設計されるのですが、実装時にはイベント重視で実装します。このギャップに戸惑うことが多いし、人に説明しても設計が手間取る部分であります。
その場合には、「振り分けAction」という考え方で設計すれば、(ちょっとオーバーヘッドはありますが)もう少し分かりやすくなると思います。

ある画面から呼び出されるActionは全て、その画面が1つだけもつ「振り分けAction」とします。
画面1つにつき1つの振り分けActionを持ちます。振り分けActionは、requestデータからイベントを判断して、実処理のActionにforwardします。これは前述のActionの連鎖を使います。

 画面→振り分けアクション→検索Action
                 →登録Action

このほうが画面遷移を考慮した設計にマッチしやすいです。呼び出すActionはあくまで振り分けActionになります。
振り分けActionが単にフラグでもって判断する場合には、StrutsにDispatchActionというクラスがあるので、それを使えば振り分けActionを作る必要がなくなります。

 画面→フラグで判断→画面Actionの検索メソッド
              →画面Actionの登録メソッド

これもありだと思います。1Actionの記述が増えすぎないように、別途ビジネスロジックは画面に関係なく設計するようにします。

私自身もStrutsに関する設計が試行錯誤状態で、Struts in Actionとか読みたいとか思っているのですが、まだ手がつかないでいます。間違っていたらコメントいただきたいです。

遭遇した実装方式で、いちばん?だったケースはこんな感じ。

  • 画面遷移単位でAction作ったけど、同じ遷移で処理が異なるケースがある。
  • そのためフラグも送信するようにして、Action内でフラグをチェックして、処理をif文で分ける。
  • 1Actionの記述が長くなりすぎたから、if文の分岐単位でロジッククラスを作って分岐する

こうすると、Actionに書いているのは、単なるif文だけで、実処理はロジッククラスと呼ばれるクラスに記述されます。
前述の振り分けActionに動きは似ていますが大きく違います。
分けるべきActionを1つにしてしまった上に、処理が多すぎるからまた分割しているという状態です。struts-configの記述が少ないだけで、実は本来struts-configに書くべきマッピングを、Action内のif文で記述しているだけです。


Struts開発での考察」への5件のフィードバック

  1. ピンバック: civic site
  2. ピンバック: civic site
  3. 簡単な画面を作成したのですが、ボタン1では画面1、ボタン2では画面2へと画面遷移を振り分けたいと思ってaction1クラスとaction2クラスを作成し処理をわけましたが、今いちstruts-configでの処理の振りわけがわかりません教えてください。

  4. こちらのページの開発パターン3を参考にしてください。
    http://www.civic-apps.com/2006/05/26/struts-dev-pattern3/

    最初の画面から呼び出されるアクション0で、処理の分岐を行い、forward先を2種類書きます。
    1つは画面1を呼び出すアクション1で、もう1つは画面2を呼び出すアクション2です。
    アクション0はアクション1,2に振り分けるだけのアクションとして動作します。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)