JavaScript - 封筒化

こんにちは、若いプログラマーさんたち!今日は、JavaScriptの封筒化(Encapsulation)の世界に楽しく飛び込んでみましょう。プログラミングが初めての方でも心配しないでください。私はあなたの親切なガイドとして、一緒にこの概念をステップバイステップで探求します。では、バーチャルのバックパックを持ち出して、始めましょう!

JavaScript - Encapsulation

封筒化とは?

想象してほしいがあります。あなたには宝箱があります。誰にでも開かれて、貴重な宝石が取られてしまいたくありませんよね?プログラミングにおける封筒化は、基本的に同じことをしています。あなたのコードを守る保護バブルに入れ、外部からのアクセスを制限するのです。

言葉を換えると、封筒化はデータとそのデータを操作するメソッドを一つのユニットやオブジェクトにまとめることです。オブジェクトの内部の詳細を隠し、必要なものだけを公開する方法です。

封筒化が必要な理由は?

「この凝った封筒化って何のために必要なの?」と思っているかもしれません。そこで、ちょっとした話をします。

昔々、スパゲティコードの地に住んでいたプログラマーがいました。その名はボブ。ボブのコードは誰にでも変更可能で、すぐに他のプログラマーが手を加え始めました。混乱が生じて!誰もコードのどの部分が何をしているか分からず、バグは兎のように増殖しました。

ここで封筒化が救世主的な役割を果たします。封筒化は以下のことを助けます:

  1. データが偶発的に変更されるのを防ぐ
  2. 複雑な実装の詳細を隠す
  3. コードをより組織的でメンテナンスしやすいものにする
  4. コードの異なる部分間の依存関係を減らす

JavaScriptにおける封筒化の方法

JavaScriptでは、封筒化を達成するためのいくつかの方法があります。それらを一つずつ見ていきましょう:

関数クロージャを使用した封筒化

クロージャはJavaScriptにおける魔法のような存在で、作成された環境を覚えます。それを利用してプライベート変数やメソッドを作成できます。以下に例を示します:

function createBankAccount(initialBalance) {
let balance = initialBalance;

return {
deposit: function(amount) {
balance += amount;
console.log(`Deposited ${amount}. New balance is ${balance}`);
},
withdraw: function(amount) {
if (amount <= balance) {
balance -= amount;
console.log(`Withdrawn ${amount}. New balance is ${balance}`);
} else {
console.log("Insufficient funds!");
}
},
getBalance: function() {
return balance;
}
};
}

const myAccount = createBankAccount(1000);
myAccount.deposit(500);  // Deposited 500. New balance is 1500
myAccount.withdraw(200); // Withdrawn 200. New balance is 1300
console.log(myAccount.getBalance()); // 1300
console.log(myAccount.balance); // undefined

この例では、balanceはプライベート変数です。createBankAccount関数の外部から直接アクセスすることはできません。私たちが公開したメソッド(depositwithdrawgetBalance)を通じてのみ操作できます。これが封筒化の実行です!

ES6クラスとプライベートフィールドを使用した封筒化

ES6クラスの導入により、より親しみやすい方法でオブジェクトを作成し、封筒化を達成することができます。以下にその方法を示します:

class BankAccount {
#balance;  // プライベートフィールド

constructor(initialBalance) {
this.#balance = initialBalance;
}

deposit(amount) {
this.#balance += amount;
console.log(`Deposited ${amount}. New balance is ${this.#balance}`);
}

withdraw(amount) {
if (amount <= this.#balance) {
this.#balance -= amount;
console.log(`Withdrawn ${amount}. New balance is ${this.#balance}`);
} else {
console.log("Insufficient funds!");
}
}

getBalance() {
return this.#balance;
}
}

const myAccount = new BankAccount(1000);
myAccount.deposit(500);  // Deposited 500. New balance is 1500
myAccount.withdraw(200); // Withdrawn 200. New balance is 1300
console.log(myAccount.getBalance()); // 1300
console.log(myAccount.#balance); // SyntaxError: Private field '#balance' must be declared in an enclosing class

この例では、#シンボルを使用してbalanceをプライベートフィールドとして宣言しています。これは、BankAccountクラス内部でのみアクセス可能であることを意味します。

ゲッターアンドセッターを使用した封筒化

ゲッターとセッターは、プロパティのアクセスや修正を定義する特別なメソッドです。オブジェクトのプロパティのセキュリティガードのような存在です。以下にその用法を見てみましょう:

class Circle {
constructor(radius) {
this._radius = radius;
}

get radius() {
return this._radius;
}

set radius(value) {
if (value <= 0) {
throw new Error("Radius must be positive");
}
this._radius = value;
}

get area() {
return Math.PI * this._radius ** 2;
}
}

const myCircle = new Circle(5);
console.log(myCircle.radius); // 5
console.log(myCircle.area);   // 78.53981633974483

myCircle.radius = 10;
console.log(myCircle.radius); // 10

myCircle.radius = -1; // Error: Radius must be positive

この例では、radiusのゲッターとセッターを使用して、半径の読み取りと修正を制御しています。セッターには半径が常に正であることを確認するチェックが含まれています。

JavaScriptにおける封筒化の利点

封筒化の方法を見てきましたので、その利点をまとめましょう:

  1. データ保護:オブジェクトの内部への不正アクセスを防ぎます。
  2. 柔軟性:内部実装を変更しても、外部のコードには影響を与えません。
  3. モジュラリティ:自己完結型のコードユニットを作成し、コードをより modular で管理しやすくします。
  4. デバッグ:データの修正可能な場所を制限することで、バグの特定がしやすくなります。
  5. 抽象化:複雑な実装の詳細を隠し、オブジェクトの使用を簡単にします。

メソッドの表

以下に、封筒化を達成するためのメソッドをまとめた表を示します:

メソッド 説明
関数クロージャ クロージャを使用してプライベート変数を作成 function createObject() { let privateVar = 0; return { getVar: () => privateVar }; }
ES6クラスとプライベートフィールド #を使用してプライベートフィールドを宣言 class MyClass { #privateField; constructor() { this.#privateField = 0; } }
ゲッターアンドセッター プロパティのアクセスと修正を制御する特別なメソッド class MyClass { get prop() { return this._prop; } set prop(value) { this._prop = value; } }

そして、皆さん!封筒化の土地を旅し、その基本的な概念からJavaScriptにおける実装方法までを探求しました。封筒化は、何を共有するか、何を秘密にするかを知る優れた秘密保持者です。あなたがプログラミングの旅を続ける中で、封筒化は信頼できる伴侶として、強固でメンテナンスしやすいコードを作成する助けになるでしょう。

続けて練習し、好奇心を持ち続け、ハッピーコーディングを!

Credits: Image by storyset