リスト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 } |
両リストは、ほぼ同じ長さになりました。どちらを選択するか趣味趣向の問題で、各人に任せま しょう。
どちらも、より美しくなどという手のかかる変更は加えていません。それは、そういう変更をす るより、もっと基本的なことが残されているからなのです。