おみくじを作ろう!! メソッド編
Javaのプログラムを作成する時に、みなさんはmain()メソッド内に全部記述していませんか? プログラムはメソッドに分けて記述するのが一般的です。しかし、初学者の人はなかなかメソッドに分けることができないようです。今回は、プログラムをメソッドに分ける考え方を解説します。
なお、メソッドの書き方については、以下の記事で説明していますので、併せて確認してください。
まず、この記事は以下のような人を対象としています。
・プログラムをメソッドに分ける考え方を知りたい
この記事を読むと、次のようなことが理解できるようになります。
・メソッドに分ける利点を理解できる
何とかプログラムを作れるようになってきたのですが、main()の中に何でも書いてしまっています。この書き方で良いのでしょうか?
目的の処理が行えれば、プログラムとしてはOKなのですが、メンテナンスのしやすさや見やすさを考えた場合、メソッドに分けて書いた方が良いですよ。
よくメソッドに分けて書くように言われるのですが、メソッドに分けようとすると、うまくプログラムが書けなくなり困っています。
では、今回は、以前作成したおみくじプログラムをメソッドに分けて記述する方法について説明しましょう!!
Java言語の勉強をまずしたい人は、下記の書籍がおススメです。かなりのページ数ですが、Java言語でプログラムを作る流れが分かりやすく紹介されていますよ。
Java言語の基本を勉強したい人は次の書籍がおススメです!!
Java言語で「じゃんけんゲーム」を作成したい人は、以下の記事を参照してください。
クラスの作り方については以下の記事で詳しく解説しています。
とりあえず、main()に書いてから分ける方法
いきなりメソッドに分けてプログラムを作り始めるのは、大変です。慣れないうちは、まずmain()メソッド内に全部書いてから、順番にメソッドに分けると良いでしょう。
ただし、メソッドに分けやすいようにプログラムを記述することが必要です。具体的には、何かの計算を行っている中で、結果を出力するプログラムを記述しないことです。
以下のプログラムは、以前の記事で作成したおみくじプログラムです。このプログラムを見て、みなさんはどう思いますか?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package omikuji; import java.util.Random; public class OmikujiIf { public static void main(String[] args) { // 0から3までの範囲で乱数を1つ生成する Random rand = new Random(); int no = rand.nextInt(4); // 取得した乱数の値によって、結果を表示する if(no == 0) { System.out.println("大吉"); }else if(no == 1) { System.out.println("中吉"); }else if(no == 2) { System.out.println("末吉"); }else { System.out.println("凶"); } } } |
「取得した乱数の値によって、おみくじの結果を判定している処理」の中に「結果を標準出力(ディスプレイ)に表示する処理」が混ざっています。このようにある目的の処理を行う中に全く別の目的の処理が混ざっていると、メソッドに分けることが難しくなります。
基本的なプログラムの書き方は「3つの構成要素」で考えることです。
プログラムを記述する場合、3つの構成要素で考えることについては以下の記事で説明しています。
メソッドに分けやすいように記述しなおすと、次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package omikuji; import java.util.Random; public class OmikujiIf2 { public static void main(String[] args) { // 0から3までの範囲で乱数を1つ生成する Random rand = new Random(); int no = rand.nextInt(4); // 取得した乱数の値によって、結果を決める String result = ""; if(no == 0) { result ="大吉"; }else if(no == 1) { result ="中吉"; }else if(no == 2) { result ="末吉"; }else { result ="凶"; } // 求めたおみくじの結果を表示する System.out.println(result); } } |
上記のように記述すると、「データの入力・準備」「データの処理」「結果の出力」の処理ごとに明確にプログラムを分けることができます。
また、今回はただおみくじの結果を表示していますが、「今日のおみくじの結果は”○○”です」と表示形式を変更する場合、最初のプログラムではSystem.out.println()が4か所あるので、4か所修正しなければなりません。人間が修正するため、修正ミスや修正忘れなどのヒューマンエラーが発生する危険性があります。修正する箇所は少なければ少ないほどメンテナンスがし易い良いプログラムと言えます。書き換えたプログラムでは、System.out.println()は1か所しかないため、修正はその1か所で済みます。
記述済みのプログラムを処理ごとにまとめる
おみくじのプログラムをじっくり見ると、3種類の処理が行われていることに気づきます。
プログラムを処理ごとに分けることができたら、今度はメソッドについて検討します。検討する内容は次の3つです。
1.メソッド名
2.仮引数の有無、データ型
3.戻り値の有無、データ型
メソッド名を考える
メソッドを作る場合、まずメソッド名を考えます。メソッド名はどんな処理を行っているのか、内容が想定できる名前を付けるようにしてください。特に決まりはありませんが、一般的に「動詞+名詞」の組み合わせで考えます。データを取得するなら「get」、データをセットするなら「set」、何か計算をするなら「calc」など、簡単な英単語を使います。インターネットではメソッドで良く利用される動詞を紹介しているサイトもありますので、困ったときは参考にしてみてください。
今回のおみくじプログラムでは、「乱数を求める処理」「乱数からおみくじの結果を求める処理」「おみくじの結果を表示する処理」があります。これらを分かりやすいメソッド名に置き換えてみましょう。
「乱数を求める処理」は「おみくじの番号を求める処理」となるので「getOmikujiNo()」、「乱数からおみくじの結果を求める処理」は「getOmikujiResult()」、「おみくじの結果を表示する処理」は「showOmikuji()」という名前にします。内容を確認しなくても、メソッド名から何を行うのか想像ができます。
仮引数の有無、データ型を考える
メソッド名を考えたら、次はそのメソッドを実行するために何かデータを利用するかを検討します。何かデータを利用するのであれば、メソッドの定義部分に仮引数としてデータ型と変数名を記述しなければなりません。
おみくじプログラムでは3つのメソッドを考えました。「おみくじの番号を求める処理:getOmikujiNo()メソッド」はおみくじの番号を新しく取得するだけで、何かデータを受け取って処理をするわけではありません。したがって、このメソッドでは仮引数の指定は不要です。
「乱数からおみくじの結果を求める処理:getOmikujiResult()メソッド」はgetOmikujiNo()メソッドで求めた番号によって、おみくじの結果を判定します。おみくじの結果を決めるためには、おみくじの番号が必要となるので、この番号を受け取る必要があります。受け取るデータはこの番号のみなので、仮引数は1つだけ指定します。また、この番号は「0から3の1つの整数(乱数)」となるので、整数型(int型)となります。
最後に「おみくじの結果を表示する処理:showOmikuji()メソッド」はgetOmikujiResult()で求めたおみくじの結果を受け取って、表示する処理を行います。おみくじの結果は「大吉」などの文字列となります。受け取るデータはこの文字列のみなので、仮引数は1つだけとなります。また、データ型は文字列(String型)となります。
以上のことから、それぞれのメソッドの定義は次の通りとなります。なお、仮引数の変数名は何でも構いません。
getOmikujiNo()
getOmikujiResult(int no)
showOmikuji(String str)
戻り値の有無、データ型を考える
最後に、それぞれのメソッドを実行した結果、何かデータを返すのか、返す場合、そのデータ型は何かを検討します。
getOmikujiNo()メソッドは、乱数(整数)を求めて、その値を返します。getOmikujiResult()はおみくじの結果(大吉、中吉など)を文字列として返します。showOmikuji()メソッドは結果を表示するだけで、実行後には何も値は返しません。したがって、それぞれのメソッドの定義は以下のようになります。
int getOmikujiNo()
String getOmikujiResult(int no)
void showOmikuji(String str)
なお、戻り値のあるメソッドを利用する場合、受け取った戻り値を変数に代入するようにしてください。戻り値が返されるのに、変数に代入していない場合、どこにもそのデータは残っていないので、プログラム中では利用することができなくなります。
アクセス修飾子を考える
メソッドの定義は以上で終了ですが、実際にコードで記述する場合、アクセス修飾子を決める必要があります。そのメソッドを外部のクラスから利用しても構わない場合は「public」、このクラス内だけで利用させたい場合は「private」をつけます。クラス内の変数などを保護したい場合は、「private」を利用する方が安全です。
また、アクセス修飾子を記述する場合、「static」キーワードを付けるのが当たり前のような書籍などがありますが、メソッドの定義では「static」は必須ではありませ。new演算子でインスタンスを作らずに定義したメソッドを使えるようにしたい場合のみ、「static」を付けます。
今回は、このクラス内だけでの利用に制限するので「private」とします。また、new演算子でインスタンスを作らずに利用できるようにしますので「static」を付けます。以上のことから、それぞれのメソッドの定義は以下のようになります。
private static int getOmikujiNo()
private static String getOmikujiResult(int no)
private static void showOmikuji(String str)
メソッドに分けたおみくじプログラム
最終的にメソッドに分けたプログラムは以下のようになります。プログラムのコード量は増えてしまいますが、main()部分は処理の概要(内容が想像できるメソッド名)だけが記述されているので、プログラムの全体像を把握しやすくなっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
package omikuji; import java.util.Random; public class OmikujiMethod { public static void main(String[] args) { // おみくじの番号を求める処理 int no = getOmikujiNo(); // 乱数からおみくじの結果を求める処理 String str = getOmikujiResult(no); // おみくじの結果を表示する処理 showOmikuji(str); } private static int getOmikujiNo() { Random rand = new Random(); return rand.nextInt(4); } private static String getOmikujiResult(int no) { String result = ""; if(no == 0) { result ="大吉"; }else if(no == 1) { result ="中吉"; }else if(no == 2) { result ="末吉"; }else { result ="凶"; } return result; } private static void showOmikuji(String str) { System.out.println(str); } } |
このプログラムを見た時に、「showOmikuji()メソッドは1行しか記述されていないで、わざわざメソッドに分ける意味があるのか?」と疑問に感じた人はいないでしょうか? 一見すると、無駄のように感じるかもしれません。しかし、たまたま今は標準出力(ディスプレイ)に出力していますが、いずれファイルに保存する処理に変更なるかもしれません。その時、メソッドに分けているとmain()部分は一切手を加えず、このメソッドだけを変更すればよいことになります。なるべくmain()部分の修正を行わなずに済むようにプログラムを記述すると、メンテナンスしやすいプログラムになります。
プログラムの勉強を始めたばかりの人は、まずmain()メソッド内に全てのプログラムを記述し、目的の処理を行うプログラムを完成させることを優先してください。動かないプログラムをいくら入力してもプログラムのスキルアップにはつながりません。プログラムの作り方に慣れてきたら、今度はmain()内のプログラムを上記の手順を参考に、メソッドに分割することにチャレンジしてみましょう。ちょっとずつ「できること」「やれること」を増やしてください。
初めから、メソッドに分ける方法
プログラムの作成に慣れてきたら、いきなりプログラムを入力せず、どのような処理で構成され、メソッドをどうするのか考えてみましょう。論文やレポートを作成する際に、いきなり文章を入力せず、まずは見出しを考える作業と似ています。
処理を考える場合、コメント文を利用して行う処理の総称を記述しています。これが最終的にメソッド名を考えるヒントとなります。やはり、
次に、記述した処理の内容から、メソッド名や引数の個数、データ型、更にはメソッドの戻り値を決定します。メソッドの処理内容を定義していないので、コンパイルエラーになりますが、気にする必要はありません。
メソッド名が記述できたら、次はそれぞれのメソッドの内容を記述(定義)していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
package omikuji; import java.util.Random; public class OmikujiMethodFirst { public static void main(String[] args) { //------------------------------------------ // データの入力・準備 //------------------------------------------ // おみくじを決める番号を用意する // 乱数(整数)がひとつ返される int no = getOmikujiNo(); //------------------------------------------ // データの処理 //------------------------------------------ // 求めた乱数を使って、おみくじの結果を求める // おみくじの結果(文字列)がひとつ返される String omikuji = getOmikujiResult(no); //------------------------------------------ // 結果の出力 //------------------------------------------ // 求めたおみくじの結果を出力する showOmikuji(omikuji); } private static int getOmikujiNo() { Random rand = new Random(); return rand.nextInt(4); } private static String getOmikujiResult(int no) { switch(no) { case 0: return "大吉"; case 1: return "中吉"; case 2: return "末吉"; default: return "凶"; } } private static void showOmikuji(String omikuji) { System.out.println(omikuji); } } |
最終的には、main()を書いてからメソッドに分けた場合とプログラムの内容は同じになります。
まとめ
今回は、プログラムをメソッドに分けて考える方法について説明しました。
・メインメソッドにはプログラム全体が簡単に理解できるように簡潔に記述する
・メソッドに分けると、プログラム全体を把握しやすい
・メソッドに分けると、修正などの作業がしやすくなる
メソッドに分けてプログラムを記述する方法を説明しましたが、いかかでした? 慣れないうちは大変かもしれませんが、メソッドから考えるという習慣をつけてください。
すぐには難しそうですが、すこしずつチャレンジしてみます。やっぱり、プログラムは3つの構成要素で考えることの大切さがわかった気がします。