2.2 関数化 関数と上手く付き合う 関数化の意義 1. 何度も同じ処理を書かなくて済む ►修正し忘れの防止 2. 処理のカタマリに名前を付けることが出来る ►パッと見似てるけど違う処理の区別 ►コードの文脈が伝わりやすくなる 3. コードが短くなり、見通しが良くなる ►言うまでもなくダラダラと長いより見やすい 2.2 関数化 2 1.何度も書かなくて済む 最初に書く時はコピペで済んでしまう ►問題は修正するとき ►例えば以下のコードに赤字部分を追加するときは? // このコードは全部で数千行ある中の至る所にコピペしてある // ちなみに弾の追加コードである for (int i = 0; i < BULLETS_LIMIT; i++) { if (bullets[i].enabled) continue; bullets[i].location = player.location; bullets[i].velocity = VAdd(VGet(0, -BULLET_SPEED, 0), player.velocity); bullets[i].enabled = TRUE; break; 何箇所あるか分からないから 追加し忘れる可能性が高い } 2.2 関数化 3 関数化すれば解決 AddBullet 関数にさっきのコードをまとめると ►使う時は AddBullet();と書くだけ ►修正する時は AddBullet 関数の中を修正するだけ これで修正し忘れる心配は無くなった 2.2 関数化 4 2.処理に名前を付けられる ただ中身を入れ替えるだけの3行のコード ►大量のコードに混ざると何なのか分からない ... int temp = a; a = b; b = temp; ... でも swap 関数として作って呼び出すと ►何がしたいのか一目瞭然 ►ついでに不要な変数が減った ... swap(&a, &b); ... 2.2 関数化 5 処理に名前を付ける意義 処理に名前を付けると文脈が明らかになる ►本来必要なコメントが不要になる 本当に美しいコードにはコメントが不要 ►読めば分かるということは質問される側も楽 関数には良い名前を付けるように心掛けよう ►悪い名前では逆に読みにくくなってしまう (もし swap 関数の名前が tarako だったら・・・?) 2.2 関数化 6 3.コードが短くなる これはあえて例を示すまでもなく・・・ ►一度定義してしまえば呼び出しは1行で済む ただそれだけのことだね 2.2 関数化 7 上手な関数化のコツ 経験的な分野なので説明が大変難しい ►みんなも色々試してコツを掴んでほしい 出来る限りの考え方を解説する ►パキッと分かるモノではない前提で聞いてね 2.2 関数化 8 「歩く」関数を考える(1) 単純な概念なのに中身が複雑なら関数化の目安 ►例えば人間が「歩く」という処理 // 10歩前に歩く処理 for (int i = 0; i < 10; i++) { if (i % 2 == 0) foot = 右足; else foot = 左足; footを上げる; footを前に出す; footを下ろす; } ※C風の擬似言語だよ! 歩くとき毎回こんな処理書いてられない ►ならば関数化しよう 2.2 関数化 9 「歩く」関数を考える(2) まずはこんな関数になった ►中身はさっきのコピペ // 10歩前に歩く関数 void walk10steps() { for (int i = 0; i < 10; i++) { if (i % 2 == 0) foot = 右足; else foot = 左足; この部分はコピペ footを上げる; footを前に出す; footを下ろす; } } 10歩以外の時はどうする・・・? 2.2 関数化 10 「歩く」関数を考える(3) 引数に歩数を渡すように変えてみた ►それに対応してループ条件が変わったね // 指定された歩数だけ前に歩く関数 void walk(int steps) { for (int i = 0; i < steps; i++) { if (i % 2 == 0) foot = 右足; else foot = 左足; footを上げる; footを前に出す; footを下ろす; } } これなら何歩でも問題ないよね 2.2 関数化 11 「歩く」関数を考える(4) より広く利用可能な性質のことを汎用性と呼ぶ ►さっきの「何歩でも問題ない」がまさにそれ ►つまり完成した「歩く」関数は汎用性が高い 汎用性が高ければ高いほど再利用が可能 ►コードを書く手間が省ける ►修正が一度で済む 何でもやってくれる関数は汎用性が低い ►その例を次のページで見てみよう 2.2 関数化 12 何でもやってくれる関数 例えばこんな関数を考える ►以下の手順を実行する関数 1. ユーザーからデータ入力を受け付ける 2. データを加工 3. データを保存 4. 完了メッセージを表示 最初から最後まで全部やってくれる良い関数 ►果たしてそうかな? 2.2 関数化 13 何でもやってくれる関数の欠陥 用途が専用化している ►ファイルからデータを読み込みたい時は? ►データを保存せずそのまま使いたい時は? ►いちいち完了メッセージを出したくない時は? 要約すると、融通が利かない ►つまり汎用性が低いってこと 2.2 関数化 14 ちょっとずつやる関数にしよう 例えば以下の関数を作ったとしよう ►データ入力を受け付けるだけの関数 ►データを加工するだけの関数 これは printf で 対処した方が良いかもね ►データを保存するだけの関数 ►(メッセージを表示するだけの関数) ファイルからデータを読み込みたい時は? ►ファイルからデータを読み込む関数を作れば良い データを保存せずそのまま使いたい時は? ►保存するだけの関数を呼ばなければ良い 2.2 関数化 15 つまり汎用性の高い関数とは 関数にする意味がある程度のカタマリ ►例えば printf でメッセージを出すだけなら無意味 かつ 専用化しないようになるべく小さい機能 ►「何でもやってくれる関数」にならないように注意 この2つを両立させると「良い関数」が出来る ►このバランスは経験によって身に付けよう ►たくさん書くことが大切 2.2 関数化 16 補足事項 見やすいコードを書こう(命名編) ►Wikiを見てね http://nanzanmmc.net/pc/lecture/game/add 2.2 関数化 17
© Copyright 2024 ExpyDoc