Day 17 のゴールと全体像
Day 17 では、メソッドを「ただ書く」段階から一歩進んで、きれいに分割して設計する力を身につけていきます。 テーマは次の 4 つです。
- 1つのメソッドに処理を書きすぎない
- メソッド名
- 単一責任の考え方
- 再利用可能な処理
ここからは、「動けばいいコード」ではなく、「読みやすくて直しやすいコード」を意識していきます。
1つのメソッドに処理を書きすぎない
ありがちな「全部 Main に書いてしまう」パターン
初心者の方が最初によくやってしまうのが、すべての処理を Main メソッドに詰め込む書き方です。
例えば、簡易プロフィール入力プログラムを、あえて「悪い例」として書いてみます。
using System;
class Program
{
static void Main(string[] args)
{
// 名前入力
Console.WriteLine("名前を入力してください:");
string name = Console.ReadLine();
// 年齢入力
Console.WriteLine("年齢を入力してください:");
int age = int.Parse(Console.ReadLine());
// 職業入力
Console.WriteLine("職業を入力してください:");
string job = Console.ReadLine();
// 趣味入力
Console.WriteLine("趣味を入力してください:");
string hobby = Console.ReadLine();
// 表示
Console.WriteLine("=== プロフィール ===");
Console.WriteLine($"名前:{name}");
Console.WriteLine($"年齢:{age}");
Console.WriteLine($"職業:{job}");
Console.WriteLine($"趣味:{hobby}");
// 年齢によるメッセージ
if (age < 20)
{
Console.WriteLine("まだまだこれからですね!");
}
else if (age < 40)
{
Console.WriteLine("脂が乗ってきましたね!");
}
else
{
Console.WriteLine("経験豊富ですね!");
}
Console.ReadLine();
}
}
C#一見すると分かりやすいですが、
- 入力
- 表示
- メッセージ判定
が全部 Main に詰め込まれていて、役割がごちゃ混ぜになっています。 このまま機能を増やしていくと、すぐに「どこを直せばいいか分からない」状態になります。
メソッドで処理を分割する
「役割ごとにメソッドを分ける」という発想
さきほどのコードを、「役割ごとにメソッドに分ける」ことを考えてみます。
- 入力する処理
- 表示する処理
- 年齢メッセージを決める処理
を、それぞれ別のメソッドにしてみます。
using System;
class Program
{
// プロフィール情報をまとめるための型がまだないので、
// ここでは個別の値を扱う形で分割していきます。
// 名前を入力するメソッド
static string InputName()
{
Console.WriteLine("名前を入力してください:");
return Console.ReadLine();
}
// 年齢を入力するメソッド
static int InputAge()
{
Console.WriteLine("年齢を入力してください:");
return int.Parse(Console.ReadLine());
}
// 職業を入力するメソッド
static string InputJob()
{
Console.WriteLine("職業を入力してください:");
return Console.ReadLine();
}
// 趣味を入力するメソッド
static string InputHobby()
{
Console.WriteLine("趣味を入力してください:");
return Console.ReadLine();
}
// プロフィールを表示するメソッド
static void ShowProfile(string name, int age, string job, string hobby)
{
Console.WriteLine("=== プロフィール ===");
Console.WriteLine($"名前:{name}");
Console.WriteLine($"年齢:{age}");
Console.WriteLine($"職業:{job}");
Console.WriteLine($"趣味:{hobby}");
}
// 年齢に応じたメッセージを返すメソッド
static string GetAgeMessage(int age)
{
if (age < 20)
{
return "まだまだこれからですね!";
}
else if (age < 40)
{
return "脂が乗ってきましたね!";
}
else
{
return "経験豊富ですね!";
}
}
static void Main(string[] args)
{
// 入力部分
string name = InputName();
int age = InputAge();
string job = InputJob();
string hobby = InputHobby();
// 表示部分
ShowProfile(name, age, job, hobby);
// 年齢メッセージ表示
string message = GetAgeMessage(age);
Console.WriteLine(message);
Console.ReadLine();
}
}
C#ここで押さえておきたいポイント
- Main は「流れを組み立てる場所」として、高レベルな処理だけを書いています。
- 入力・表示・メッセージ判定は、それぞれ専用のメソッドに分かれています。
- どのメソッドが何をしているか、名前から分かるようになっています。
これが、「1つのメソッドに処理を書きすぎない」という考え方の具体例です。
メソッド名と単一責任の考え方
単一責任とは
単一責任とは、
1つのメソッドは、1つのはっきりした役割だけを持つ
という考え方です。
- 入力するメソッドは「入力だけ」
- 表示するメソッドは「表示だけ」
- 判定するメソッドは「判定だけ」
というように、役割を分けていきます。
メソッド名は「何をするか」が分かるように
メソッド名は、そのメソッドの責任を表す名前にすることが大切です。
InputName→ 名前を入力するShowProfile→ プロフィールを表示するGetAgeMessage→ 年齢に応じたメッセージを取得する
このように、
- 「動詞 + 目的語」
- 「何をするか」が一目で分かる
名前にしておくと、コードを読む人(未来の自分も含めて)が理解しやすくなります。
再利用可能な処理を意識する
「また使いそうだな」と思ったらメソッドにする
メソッド分割のコツは、
「この処理、また別のところでも使いそうだな」
と思ったら、迷わずメソッドに切り出すことです。
例えば、区切り線を表示する処理は、いろいろな場面で使えます。
static void PrintSeparator()
{
Console.WriteLine("================================");
}
C#これを使うと、どんなプログラムでも簡単に見やすくできます。
static void Main(string[] args)
{
PrintSeparator();
Console.WriteLine("メニュー");
PrintSeparator();
Console.ReadLine();
}
C#「再利用できるか?」を分割の判断材料にする
- 何度も同じようなコードを書いている
- 別の画面や別の機能でも同じ処理が必要になりそう
というときは、
- その処理をメソッドにする
- 引数と戻り値を使って汎用的にする
ことを意識すると、再利用可能な部品として育っていきます。
練習テンプレート:メソッド分割の型
入力・処理・表示を分ける基本テンプレート
using System;
class Program
{
// 入力を担当するメソッド
static int InputNumber()
{
Console.WriteLine("整数を入力してください:");
return int.Parse(Console.ReadLine());
}
// 処理(ここでは 2 倍にする)を担当するメソッド
static int DoubleNumber(int value)
{
return value * 2;
}
// 表示を担当するメソッド
static void ShowResult(int original, int doubled)
{
Console.WriteLine($"元の値:{original}");
Console.WriteLine($"2倍の値:{doubled}");
}
static void Main(string[] args)
{
int n = InputNumber(); // 入力
int d = DoubleNumber(n); // 処理
ShowResult(n, d); // 表示
Console.ReadLine();
}
}
C#このテンプレートをベースに、
- 処理部分を「合計」「平均」「判定」などに変えてみる
- 入力を複数にしてみる
- 表示内容を増やしてみる
といった練習をすると、「メソッドを役割ごとに分ける」感覚が自然に身についていきます。
Day 17 のまとめ
Day 17 では、
- 1つのメソッドに処理を書きすぎない
- メソッド名で「何をするか」を表現する
- 単一責任の考え方(1メソッド1役割)
- 再利用可能な処理をメソッドとして切り出す
という 4 つの視点から、メソッドの分割と設計を学びました。
これまで学んできた制御構文やメソッドを、「どう組み立てるか」というレベルで考え始めると、 コードはぐっと読みやすく、直しやすくなります。
ぜひ、
- 既に書いたコードを見直して、「ここはメソッドに分けられないか?」と考えてみる
- メソッド名を「何をするか」が分かる名前に整えてみる
- 入力・処理・表示を分けるテンプレートを、自分なりにアレンジしてみる
といった練習を通して、「設計を意識したメソッド分割」の感覚を育てていってください。
Day 17 電卓課題のゴール
Day 17 の課題では、電卓プログラムをメソッドに分割することで、
- 1つのメソッドに処理を書きすぎない
- メソッド名で役割をはっきりさせる
- 単一責任の考え方
- 再利用可能な処理
を体で覚えていくことを目指します。
ここでは、電卓の基本機能を次の 4 つのメソッドに分割します。
Add():足し算Subtract():引き算Multiply():掛け算Divide():割り算
電卓を「1つの巨大メソッド」で書いた場合
まずは、あえて「悪い例」として、すべての処理を Main に詰め込んだ電卓をイメージしてみます。
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("1つ目の数値を入力してください:");
double a = double.Parse(Console.ReadLine());
Console.WriteLine("2つ目の数値を入力してください:");
double b = double.Parse(Console.ReadLine());
Console.WriteLine("演算を選んでください(+ - * /):");
string op = Console.ReadLine();
double result = 0;
if (op == "+")
{
result = a + b;
}
else if (op == "-")
{
result = a - b;
}
else if (op == "*")
{
result = a * b;
}
else if (op == "/")
{
if (b == 0)
{
Console.WriteLine("0 で割ることはできません。");
Console.ReadLine();
return;
}
result = a / b;
}
else
{
Console.WriteLine("不正な演算子です。");
Console.ReadLine();
return;
}
Console.WriteLine($"結果:{result}");
Console.ReadLine();
}
}
C#一見すると動きますが、
- 入力
- 演算の選択
- 計算処理
- エラー処理
が全部 Main に詰め込まれていて、役割がごちゃ混ぜになっています。 機能を増やしていくと、すぐに「どこを直せばいいか分からない」状態になります。
電卓をメソッドに分割する方針
単一責任で考える
電卓の処理を、次のように役割ごとに分けて考えます。
- 計算する責任:足し算・引き算・掛け算・割り算
- 入力する責任:数値や演算子を入力してもらう
- 表示する責任:結果やメッセージを表示する
このうち、今回の課題では特に「計算する責任」を 4 つのメソッドに分割します。
Add(double a, double b)Subtract(double a, double b)Multiply(double a, double b)Divide(double a, double b)
それぞれが「1つの計算だけ」を担当するようにします。
計算メソッドを定義する
Add:足し算メソッド
// 2つの数値の足し算を行うメソッド
static double Add(double a, double b)
{
// a + b の結果をそのまま返します
return a + b;
}
C#Subtract:引き算メソッド
// 2つの数値の引き算を行うメソッド
static double Subtract(double a, double b)
{
// a - b の結果を返します
return a - b;
}
C#Multiply:掛け算メソッド
// 2つの数値の掛け算を行うメソッド
static double Multiply(double a, double b)
{
// a * b の結果を返します
return a * b;
}
C#Divide:割り算メソッド(0割りチェック付き)
割り算は「0 で割る」という危険があるので、少しだけ慎重に書きます。
// 2つの数値の割り算を行うメソッド
static double Divide(double a, double b)
{
if (b == 0)
{
// 0 で割ろうとした場合は、メッセージを表示して 0 を返します
Console.WriteLine("0 で割ることはできません。結果は 0 とします。");
return 0;
}
return a / b;
}
C#ここでの重要ポイント:
- 各メソッドは「1つの計算だけ」を担当しています。
- メソッド名から「何をするか」がはっきり分かります。
- Divide だけは、割り算の責任に加えて「安全性の確保」という責任も持っていますが、 それも「割り算を安全に行う」という 1 つの目的にまとまっています。
電卓のメイン処理を「組み立てる」
メソッドを部品として使う
計算メソッドを定義したら、Main では「部品を組み合わせる」ことに集中できます。
using System;
class Program
{
// 足し算
static double Add(double a, double b)
{
return a + b;
}
// 引き算
static double Subtract(double a, double b)
{
return a - b;
}
// 掛け算
static double Multiply(double a, double b)
{
return a * b;
}
// 割り算(0割りチェック付き)
static double Divide(double a, double b)
{
if (b == 0)
{
Console.WriteLine("0 で割ることはできません。結果は 0 とします。");
return 0;
}
return a / b;
}
static void Main(string[] args)
{
// 数値入力
Console.WriteLine("1つ目の数値を入力してください:");
double a = double.Parse(Console.ReadLine());
Console.WriteLine("2つ目の数値を入力してください:");
double b = double.Parse(Console.ReadLine());
// 演算子入力
Console.WriteLine("演算を選んでください(+ - * /):");
string op = Console.ReadLine();
double result;
// 演算子に応じて、対応するメソッドを呼び出します
if (op == "+")
{
result = Add(a, b); // 足し算メソッドを呼び出し
}
else if (op == "-")
{
result = Subtract(a, b); // 引き算メソッドを呼び出し
}
else if (op == "*")
{
result = Multiply(a, b); // 掛け算メソッドを呼び出し
}
else if (op == "/")
{
result = Divide(a, b); // 割り算メソッドを呼び出し
}
else
{
Console.WriteLine("不正な演算子です。+ - * / のいずれかを入力してください。");
Console.ReadLine();
return;
}
// 結果表示
Console.WriteLine($"結果:{result}");
Console.ReadLine();
}
}
C#ここで押さえておきたいポイント
- Main は「電卓の流れ」を書くだけで、計算の中身はメソッドに任せています。
- 各計算メソッドは「単一責任」で、1つの演算だけを担当しています。
- メソッド名が分かりやすいので、コードを読むときに「何をしているか」がすぐに分かります。
単一責任と再利用性の関係
「責任がはっきりしているほど、再利用しやすい」
Addは「2つの数値を足す」だけSubtractは「2つの数値を引く」だけMultiplyは「2つの数値を掛ける」だけDivideは「2つの数値を安全に割る」だけ
というように、責任がはっきりしているメソッドは、
- 別のプログラムでもそのまま使える
- テストしやすい
- バグが出たときに「どこを疑えばいいか」が分かりやすい
というメリットがあります。
例えば、将来「複雑な数式計算プログラム」を作るときにも、 この 4 つのメソッドはそのまま部品として再利用できます。
練習テンプレート:電卓メソッドを拡張してみる
べき乗や剰余を追加してみる
課題をさらに発展させて、
Power():べき乗(a の b 乗)Mod():剰余(a を b で割った余り)
などを追加してみるのも良い練習になります。
// a の b 乗を計算するメソッド
static double Power(double a, double b)
{
return Math.Pow(a, b); // Math.Pow は C# 標準のべき乗関数です
}
// a を b で割った余りを返すメソッド
static double Mod(double a, double b)
{
if (b == 0)
{
Console.WriteLine("0 で割ることはできません。結果は 0 とします。");
return 0;
}
return a % b;
}
C#Main 側で、
- 演算子に
^や%を追加する - 対応するメソッドを呼び出す
という形で拡張していくと、
「メソッドを部品として増やしながら、電卓を育てていく」
感覚が身についていきます。
Day 17 電卓課題のまとめ
この課題では、電卓を次の 4 つのメソッドに分割しました。
Add()Subtract()Multiply()Divide()
その過程で、
- 1つのメソッドに処理を書きすぎない
- メソッド名で「何をするか」を表現する
- 単一責任の考え方(1メソッド1役割)
- 再利用可能な処理をメソッドとして切り出す
という Day 17 のテーマを、具体的なコードとして体験しました。
ぜひ、
- 自分で演算を追加してみる(べき乗、剰余、絶対値など)
- 入力部分や表示部分もメソッドに分けてみる
- 「この処理は別のプログラムでも使えそうか?」と考えながらメソッドを設計してみる
といった練習を通して、「メソッドを分割して設計する力」を少しずつ育てていってください。
