『Cプログラミング診断室』目次次(第11章 奇っ怪な条件 クライアント・サーバモデル)

第11章 奇っ怪な条件

酷似関数


リスト11−1には、次の4つの関数があります。

    void  mac_up_event( xwin, event )
    void  mac_down_event( xwin, event )
    void  mac_left_event( xwin, event )
    void  mac_right_event( xwin, event )
名前は、上下左右(up,down,left,right)の部分が違うだけです。関数の中身の方も、実はほとんど 同じです。違いのある行は、
  1             関数名 mac_up_event
  25〜27        mac_yの設定(減少)
  52            関数名 mac_down_event
  76〜82        mac_yの設定(増加)
  107           関数名 mac_left_event
  131〜133      mac_xの設定(減少)
  158           関数名 mac_right_event
  182〜189      mac_xの設定(減少)
に過ぎません。ということは、9割までが同じということです。

ほとんど同じものは1つで済ませようという「横着心」が働いてきませんか。再三書いてきまし たが、ほとんど同じことを4回書くと、バグが入っていた場合、4個所直さなければいけません。 普通の、私のような者には、4個所をきちんと正確に直す自信はありません。何度もこのような修 正をすれば、間違える自信だけはあります。

左右上下の4方向の処理内容は酷似しているのだから、なんとか工夫して1つにして、将来のバ グや機能変更などを楽しようと思いませんか。共通の関数は、4方向を識別する必要があるので、 それぞれの方向をchar型のデータ'u','d','l','r'を引数に加えます。逆に、引数中のウィンド xwinは未使用なので、削除してしまいましょう。ただし、mac_up_event などの4つの関数の引数 は、これらがイベントハンドラであるため、ユーザが引数の並びを勝手に決めることはできず、使 用するしないに関わらず、このように書く決まりになっているので、引数xwinは絶対に省略できま せん。このあたりの詳細はXウィンド(X-View)のマニュアル(参考文献[11-1])を見てください。

そうすることで、4つの関数は、それぞれ、

    mac_common_event( event, 'u' );
    mac_common_event( event, 'd' );
    mac_common_event( event, 'l' );
    mac_common_event( event, 'r' );
という呼び出しを1行だけ含む単純なものになり、全ての処理は共通関数mac_common_eventにまと められます。以上の考えで書き直したプログラムがリスト11−2です。

リスト11−2 修正版(その1)全体を共通関数化

     1  static  void    mac_common_event();
     2  
     3  void    mac_up_event( xwin, event )
     4  Xv_Window   xwin;
     5  Event       *event;
     6  {
     7          mac_common_event( event, 'u' );
     8  }
     9  
    10  void    mac_down_event( xwin, event )
    11  Xv_Window   xwin;
    12  Event       *event;
    13  {
    14          mac_common_event( event, 'd' );
    15  }
    16  
    17  void    mac_left_event( xwin, event )
    18  Xv_Window   xwin;
    19  Event       *event;
    20  {
    21          mac_common_event( event, 'l' );
    22  }
    23  
    24  void    mac_right_event( xwin, event )
    25  Xv_Window   xwin;
    26  Event       *event;
    27  {
    28          mac_common_event( event, 'r' );
    29  }
    30  
    31  static  void    mac_common_event( event, direction )
    32  Event       *event;
    33  char        direction;  /* 'u', 'd', 'l', 'r'   */
    34  {
    35          int         x;
    36          int         y;
    37          RECT        rectdisp;
    38          RECT        rectbase;
    39          POINT       point1;
    40          POINT       point2;
    41          Display     *dpy;
    42          Window      win_disp;
    43          Xv_Window   xwin_disp;
    44  
    45          if( event_is_ascii( event ) )
    46                  return;
    47          if( ! event_is_down( event ) )
    48                  return;
    49          if( ! ( event_action( event ) == ACTION_SELECT ||
    50                  event_action( event ) == MS_LEFT ||
    51                  event_action( event ) == ACTION_ADJUST ||
    52                  event_action( event ) == MS_MIDDLE ||
    53                  event_action( event ) == ACTION_MENU ||
    54                  event_action( event ) == MS_RIGHT ) )
    55                          return;
    56  
    57          switch( direction ) {
    58          case 'u':       /* up    */
    59                  mac_y -= mac_height / mac_mag / 2;
    60                  break;
    61          case 'd':       /* down  */
    62                  mac_y += mac_height / mac_mag / 2;
    63                  break;
    64          case 'l':       /* left  */
    65                  mac_x -= mac_width / mac_mag / 2;
    66                  break;
    67          case 'r':       /* right */
    68                  mac_x += mac_width / mac_mag / 2;
    69                  break;
    70          }
    71  
    72          if( mac_x > xdot - mac_width / mac_mag )
    73                  mac_x = xdot - mac_width / mac_mag;
    74          if( mac_x < 0 )
    75                  mac_x = 0;
    76          if( mac_y > ydot - mac_height / mac_mag )
    77                  mac_y = ydot - mac_height / mac_mag;
    78          if( mac_y < 0 )
    79                  mac_y = 0;
    80  
    81          mac_posx = mac_x + mac_width / mac_mag / 2;
    82          mac_posy = mac_y + mac_height/ mac_mag / 2;
    83          rectdisp.x = 0;
    84          rectdisp.y = 0;
    85          rectdisp.size_x = mac_width;
    86          rectdisp.size_y = mac_height;
    87          rectbase.x = mac_x;
    88          rectbase.y = mac_y;
    89          xwin_disp = (Xv_Window)canvas_paint_window( mac_canvas );
    90          dpy = (Display *)xv_get( base_frame, XV_DISPLAY );
    91          win_disp = (Window)xv_get( xwin_disp, XV_XID );
    92          mac_cur = OFF;
    93          disp_data( (PRECT)&rectdisp, (PRECT)&rectbase,
    94                         mac_mag, (PPOINT)&mac_point,
    95                         mac_image_ad, mac_image -> bytes_per_line,
    96                         ON );
    97          XPutImage( dpy, win_disp, mac_paint_gc, mac_image,
    98                     rectdisp.x, rectdisp.y,
    99                     rectdisp.x, rectdisp.y,
   100                     rectdisp.size_x, rectdisp.size_y );
   101  }

あるいは、同じ部分だけを別の関数にして、左右上下の処理関数からそれらを呼び出すようにす る案もあります。4方向それぞれで計算が異なりますが、その部分は元の関数に残し、完全に共通 に出来る部分をevent_checkとmac_do_eventの2関数にしました(リスト11−3)。

リスト11−3 修正版(その2)共通部分だけを別関数化

     1  static  int     event_check();
     2  static  void    mac_do_event();
     3  
     4  void    mac_up_event( xwin, event )
     5    Xv_Window   xwin;
     6    Event       *event;
     7  {
     8          if( event_check( event ) ) {
     9                  mac_y -= mac_height / mac_mag / 2;
    10                  mac_do_event();
    11          }
    12  }
    13  
    14  void    mac_down_event( xwin, event )
    15    Xv_Window   xwin;
    16    Event       *event;
    17  {
    18          if( event_check( event ) ) {
    19                  mac_y += mac_height / mac_mag / 2;
    20                  mac_do_event();
    21          }
    22  }
    23  
    24  void    mac_left_event( xwin, event )
    25    Xv_Window   xwin;
    26    Event       *event;
    27  {
    28          if( event_check( event ) ) {
    29                  mac_x -= mac_width / mac_mag / 2;
    30                  mac_do_event();
    31          }
    32  }
    33  
    34  void    mac_right_event( xwin, event )
    35    Xv_Window   xwin;
    36    Event     *event;
    37  {
    38          if( event_check( event ) ) {
    39                  mac_x += (int)((DOUBLE)mac_width / mac_mag ) / 2;
    40                  mac_do_event();
    41          }
    42  }
    43  
    44  static  int     event_check( event )
    45    Event         *event;
    46  {
    47          if( !event_is_ascii( event ) )
    48              if( event_is_down( event ) &&
    49                   ( event_action( event ) == ACTION_SELECT ||
    50                     event_action( event ) == MS_LEFT ||
    51                     event_action( event ) == ACTION_ADJUST ||
    52                     event_action( event ) == MS_MIDDLE ||
    53                     event_action( event ) == ACTION_MENU ||
    54                     event_action( event ) == MS_RIGHT ) )
    55                  return  TRUE;
    56  
    57          return  FALSE;
    58  }
    59  
    60  static  void    mac_do_event()
    61  {
    62          int         x;
    63          int         y;
    64          RECT        rectdisp;
    65          RECT        rectbase;
    66          POINT       point1;
    67          POINT       point2;
    68          Display     *dpy;
    69          Window      win_disp;
    70          Xv_Window   xwin_disp;
    71  
    72          if( mac_x > xdot - mac_width / mac_mag )
    73                  mac_x = xdot - mac_width / mac_mag;
    74          if( mac_x < 0 )
    75                  mac_x = 0;
    76          if( mac_y > ydot - mac_height / mac_mag )
    77                  mac_y = ydot - mac_height / mac_mag;
    78          if( mac_y < 0 )
    79                  mac_y = 0;
    80  
    81          mac_posx = mac_x + mac_width / mac_mag / 2;
    82          mac_posy = mac_y + mac_height/ mac_mag / 2;
    83          rectdisp.x = 0;
    84          rectdisp.y = 0;
    85          rectdisp.size_x = mac_width;
    86          rectdisp.size_y = mac_height;
    87          rectbase.x = mac_x;
    88          rectbase.y = mac_y;
    89          xwin_disp = (Xv_Window)canvas_paint_window( mac_canvas );
    90          dpy = (Display *)xv_get( base_frame, XV_DISPLAY );
    91          win_disp = (Window)xv_get( xwin_disp, XV_XID );
    92          mac_cur = OFF;
    93          disp_data( (PRECT)&rectdisp, (PRECT)&rectbase,
    94                         mac_mag, (PPOINT)&mac_point,
    95                         mac_image_ad, mac_image -> bytes_per_line,
    96                         ON );
    97          XPutImage( dpy, win_disp, mac_paint_gc, mac_image,
    98                     rectdisp.x, rectdisp.y,
    99                     rectdisp.x, rectdisp.y,
   100                     rectdisp.size_x, rectdisp.size_y );
   101  }

両リストは、ほぼ同じ長さになりました。どちらを選択するか趣味趣向の問題で、各人に任せま しょう。

どちらも、より美しくなどという手のかかる変更は加えていません。それは、そういう変更をす るより、もっと基本的なことが残されているからなのです。


Copyright1996 Hirofumi Fujiwara. No reproduction or republication without written permission
『Cプログラミング診断室』目次次(第11章 奇っ怪な条件 クライアント・サーバモデル)