COBOLデザインパターン(Exit)

前回は、判断の部分をセクションに書き出して、メインのルーチンを簡単にしました。
http://d.hatena.ne.jp/Iwamoto/20080722/1216738870


なんというかくさいものにはフタ的な方法でしたが、今回のパターンは、道草食わずに処理を戻すというお利巧さんのパターンです。チェックロジックなどでは、よく使います。


前回の最後のソースでは、IF文のネストが深く、一見して何をしているのかよくわかりません。

      * Switch2.cob : 複雑な条件判断はスイッチを用いて判定と処理を分割する
       IDENTIFICATION  DIVISION.
       PROGRAM-ID.     SWITCH2.
       ENVIRONMENT     DIVISION.
       DATA            DIVISION.
       WORKING-STORAGE SECTION.
       01 IN-REC.
         05 HH         PIC 99.
         05 FILLER     PIC X(01).
         05 MM         PIC 99.
       01 SW-AMPM      PIC 9.
       01 CNS-AMPM.
         05 GOZEN      PIC 9 VALUE 1.
         05 SHOGO      PIC 9 VALUE 2.
         05 GOGO       PIC 9 VALUE 3.
         05 OWARI      PIC 9 VALUE 4.
       PROCEDURE       DIVISION.
       LOOP. 
       DISPLAY '時間をHH:MM 形式で入力してね'
       ACCEPT IN-REC.
       
       MOVE 0          TO SW-AMPM.
       PERFORM S001-AMPM.

       EVALUATE SW-AMPM
         WHEN GOZEN
           DISPLAY '午前です。'
         WHEN SHOGO
           DISPLAY '正午です。'
         WHEN GOGO
           DISPLAY '午後です。'
         WHEN OWARI
           DISPLAY '終わりにします。'
           STOP RUN
         WHEN OTHER
           DISPLAY '時刻ではありません。'
       END-EVALUATE.
       GO TO LOOP. 
       STOP RUN.
       ***********************************************************************
       S001-AMPM SECTION.

       IF HH < 12 
         THEN
           MOVE GOZEN      TO SW-AMPM
         ELSE
           IF HH = 12 AND MM = 0
             THEN
               MOVE SHOGO   TO SW-AMPM
             ELSE
               IF HH = 99 AND MM = 99
                 THEN 
                   MOVE OWARI TO SW-AMPM
                 ELSE
                   MOVE GOGO  TO SW-AMPM
               END-IF
           END-IF
       END-IF.

       EXIT.

ELSE IFが使えたならこんなことにはならないのですが・・・
まあ、それはそれとしてレベルをそろえましょう。

       S001-AMPM SECTION.
         IF HH = 99 AND MM = 99
           THEN 
             MOVE OWARI      TO SW-AMPM
             GO TO S001-AMPM-EX
         END-IF.

         IF HH < 12 
           THEN
             MOVE GOZEN      TO SW-AMPM
             GO TO S001-AMPM-EX
         END-IF.

         IF HH = 12 AND MM = 0
           THEN
             MOVE SHOGO      TO SW-AMPM
             GO TO S001-AMPM-EX
         END-IF.

         MOVE GOGO           TO SW-AMPM.
       S001-AMPM-EX.
       EXIT.

用事がすんだら、とっととセクションから出て行ってます。
このときにGO TOを使うので、嫌がる人がいるのですが、セクションの目的がはっきりしているのであれば問題が起こることはまずありません。理由は、GO TOがあることで、処理が明確になるからです。
(ほかの言語では、BREAKやRETURNなどが存在します。うらやまい。)


逆に、処理内容が明確でない場合にGO TOを使うのは悲劇の元です・・・


このパターンのメリットは、スイッチをつける優先順がはっきりすること。
さらに、ロジックの追加に強くなることです。


ちょっとやってみます。
たとえば、現在、分に60以上の数値を入力可能で、時間も24以上が入力可能です。
これを禁止するエラー判定ロジックを追加して見ます。

       S001-AMPM SECTION.
         IF HH = 99 AND MM = 99
           THEN 
             MOVE OWARI      TO SW-AMPM
             GO TO S001-AMPM-EX
         END-IF.

         IF HH > 23
         OR MM > 59
           THEN
             MOVE ERR        TO SW-AMPM
             GO TO S001-AMPM-EX
         END-IF.

         IF HH < 12
           THEN
             MOVE GOZEN      TO SW-AMPM
             GO TO S001-AMPM-EX
         END-IF.

         IF HH < 12
           THEN
             MOVE GOZEN      TO SW-AMPM
             GO TO S001-AMPM-EX
         END-IF.

         IF HH = 12 AND MM = 0
           THEN
             MOVE SHOGO      TO SW-AMPM
             GO TO S001-AMPM-EX
         END-IF.

         MOVE GOGO           TO SW-AMPM.
       S001-AMPM-EX.
       EXIT.

こんな感じ、ネストさせたIF文では、下位の階層を一段ずつずらすことになるので、「みなかったことにする。」コーダーさんもいらっしゃいますし、インデントを無視して追加するコーダーさんもいます。最悪な話ですけど・・・


とにかくこの方法は、蛇腹のようになったIF文のネストをすっきりさせる方法です。