カプセル化
Encapsulation
カプセル化とは、データ(状態)とそれを操作する処理(振る舞い)を一つにまとめ、外部から直接データを変更できないように隠す(隠蔽する)オブジェクト指向プログラミングの重要な設計手法です。
🐾 猫で例えると?
この写真の茶トラ猫ちゃんは、自分の体(複雑な内部構造や大切なデータ)を箱の中にすっかり隠し、外の世界とは「顔」だけでやり取りしています。このように「不用意に触られないよう大切な中身を保護し、必要な部分(窓口)だけを外に見せる」という仕組みは、プログラミングにおけるカプセル化(情報隠蔽)の概念そのものです。
💻 プログラミングにおける「カプセル化」とは?
カプセル化では、内部の状態と操作をまとめ、利用側が内部の表現へ依存しすぎないようにします。クラスのフィールドを隠すだけでなく、「どの状態を許すか」「どの操作で変更できるか」を決めることが重要です。
そこでカプセル化の出番です。データ(変数)をクラスというカプセルの中に閉じ込め、外部からは直接触れないように(private に)設定します。そして、データを読み書きするための専用の窓口となるメソッド(public)だけを用意することで、安全で壊れにくいプログラムを作ることができます。
⚠️ カプセル化の仕組みとメリット
カプセル化を実装する最大のメリットは「不正な値の混入を防ぐこと」と「内部の仕組みが変わっても、外側には影響を与えないこと(保守性の向上)」です。
TypeScriptでのカプセル化の実装例
次のJavaScript例では、#weightを直接公開せず、作成時も更新時も同じ検査を通します。説明のための数値管理であり、猫の適正体重を判定するものではありません。
class Cat {
#weight;
constructor(initialWeight) {
this.setWeight(initialWeight);
}
getWeight() {
return this.#weight;
}
setWeight(value) {
if (!Number.isFinite(value) || value <= 0) {
throw new RangeError("体重は有限の正の数で指定してください");
}
this.#weight = value;
}
}
const cat = new Cat(4);
console.log(cat.getWeight()); // 4 この例は負数だけでなくNaNやInfinity、文字列も拒否します。TypeScriptのprivateは主に型検査上の制約で、JavaScriptの#privateと実行時の性質が異なります。また、privateは暗号化や利用者に対するアクセス権限の代わりにはなりません。
🛠️ カプセル化を賢く使うためのポイント
設計をする上で、カプセル化を上手く活用するためのルールがあります。
- 守る条件を先に決める: 作成直後にも、どの操作の後にも成り立つ条件を整理します。コンストラクターだけが検査を抜けたり、取得した内部オブジェクトを外部から書き換えられたりしないか確認します。
- 「何をするか」だけを見せ、「どうやるか」は隠す: 外部から呼び出すメソッド名(顔)だけをシンプルにし、内部の複雑な計算ロジック(体の中身)は隠すことで、使う側は難しいことを考えずに機能を利用できます。
- 何でもかんでもゲッター/セッターを作らない: カプセル化したのに、すべての変数に対して無条件でゲッターとセッターを作ってしまうと、実質公開しているのと同じになってしまいます。必要な分だけ窓口を作るのが鉄則です。
箱から顔だけを見せる猫のように、カプセル化では必要な操作を外に公開します。値を隠すだけでなく、公開した操作を通すことで不正な状態を作らないようにするのが設計の要点です。どこから状態を変更できるかを確認してみましょう。