C#のカプセル化とは?Studentクラスのpublicをprivateに変えて理解しよう
前回までのチュートリアルで、みなさんはすでにこのStudentクラスを書いて、実行して、結果を確認していると思います。
using System;
namespace StudentClassTutorial
{
internal class Program
{
static void Main(string[] args)
{
Student student1 = new Student();
student1.Name = "田中";
student1.Score = 80;
Console.WriteLine($"{student1.Name}さんの点数は{student1.Score}点です。");
}
}
class Student
{
public string Name;
public int Score;
}
}
student1.Name = "田中";
student1.Score = 80; のように、フィールドに直接値を入れるだけの、シンプルなコードです。動かしてみると、ちゃんと「田中さんの点数は80点です。」と表示されたはずです。
このコード、動くには動きます。ですが、実は少し危ういところがあります。今回はこのコードを起点に、「カプセル化」という考え方を学んでいきましょう。
1. このコードの弱点 — publicフィールドの危うさ
NameとScoreはpublicなフィールドです。publicは「クラスの外からも自由にアクセスできる」という意味でしたね。つまり、このクラスを使う側は、Scoreにどんな値でも入れられてしまいます。
student1.Score = -50;
これも、コンパイルエラーにはなりません。実行もできてしまいます。でも、テストの点数がマイナス50点なんて、現実にはあり得ませんよね。同じように、
student1.Score = 100000;
10万点、というのもおかしな話です。Studentクラス自身は、「点数は0点から100点まで」というルールを何も知りません。だから、外から変な値を入れられても、それを止める仕組みがないのです。

このように、publicなフィールドをそのまま公開していると、「このクラスをどう使ってほしいか」というルールを、クラス自身が守れません。使う側のミス一つで、簡単にデータが壊れてしまいます。
2. 解決策 — フィールドをprivateにして、プロパティで守る
そこで登場するのが「カプセル化」です。考え方はシンプルで、次の2つを組み合わせます。
- フィールド(
_nameや_score)はprivateにして、クラスの外から直接触れないようにする - 代わりに
publicなプロパティを用意し、値を出し入れするための「窓口」にする
プロパティのset(値を設定する処理)の中で「その値は正しいか?」をチェックすれば、おかしな値をそもそも受け付けないクラスにできます。図にすると、こんなイメージです。
Scoreに値を代入しようとすると、まず「0~100の範囲か?」という関所を通ります。範囲内ならそのまま保存され、範囲外なら拒否されます。外から見るとstudent1.Score = 80;と書くだけなのは変わりませんが、内部では静かにこのチェックが働いているわけです。
3. 実際に書き換えてみよう
それでは、Studentクラスを書き換えてみましょう。

ポイントは次の4つです。
_nameと_scoreはprivateにして、クラスの外から直接書き換えられないようにしているNameプロパティは今のところ単純な受け渡しだが、これも立派な「窓口」であり、呼び出し側のコードは変わらないScoreのsetの中で、0未満または100より大きい値が来たらメッセージを出して処理を止めている- チェックを通過した値だけが、最後に
_score = value;で保存される
コード全体は次のようになります。
using System;
namespace StudentClassTutorial
{
internal class Program
{
static void Main(string[] args)
{
Student student1 = new Student();
student1.Name = "田中";
student1.Score = 80;
Console.WriteLine($"{student1.Name}さんの点数は{student1.Score}点です。");
student1.Score = -50;
Console.WriteLine($"{student1.Name}さんの点数は{student1.Score}点です。");
}
}
class Student
{
private string _name;
private int _score;
public string Name
{
get { return _name; }
set { _name = value; }
}
public int Score
{
get { return _score; }
set
{
if (value < 0 || value > 100)
{
Console.WriteLine("点数は0~100の範囲で入力してください。");
return;
}
_score = value;
}
}
}
}
注目してほしいのは、Mainメソッド側の書き方が、student1.Score = -50;の行が増えたこと以外はほとんど変わっていない、という点です。student1.Name = "田中";もstudent1.Score = 80;も、書き換え前とまったく同じ書き方のまま使えます。
Scoreに80を代入したときは、これまで通り「田中さんの点数は80点です。」と表示されます。ところが、次に-50を代入しようとすると、コンソールに「点数は0~100の範囲で入力してください。」と表示され、_scoreの値は変わりません。そのため、その後のConsole.WriteLineでも点数は80点のまま表示されます。おかしな値がこっそり紛れ込むことは、もうありません。
4. まとめ:この書き換えで得られる4つのメリット
publicなフィールドをprivate+プロパティに書き換えるだけで、クラスは大きく変わります。

- データを守る:不正な点数(マイナスや100点超)を弾ける
- 誤操作を防ぐ:呼び出し側が知らないうちにデータを壊してしまうことを防げる
- 変更に強い:後からチェックのルールを変えたくなっても、
Studentクラスの中だけを直せばいい - 呼び出し側はそのまま:
Main()側のコードはほとんど変更しなくていい
おわりに
「publicなフィールドを、private+プロパティに変える」— これだけのことですが、クラスに「自分の身は自分で守る」という責任を持たせることができます。これこそが、カプセル化の本質です。
みなさんが最初に書いたStudentクラスも、ぜひ今回のように書き換えて、Scoreに変な値を入れようとしたらどうなるか、実際に試してみてください。「動くコード」から「壊れにくいコード」へと一歩進んだ実感が得られるはずです。







ディスカッション
コメント一覧
まだ、コメントがありません