カプセル化
カプセル化とは内部情報を隠蔽すること
内部情報を具体的に言うと、クラスの属性値、メソッドの処理内容です。隠蔽とはクラス外部から見えなくするということですが、その目的が重要です。
クラスの依存関係
記事冒頭の概要部分で、複数のオブジェクトを組み合わせてプログラムを作成すると説明しました。例えば、AとBという2つのクラスがあったとします。AでBをインスタンス化し、Bのメソッドを呼び出すといった様に組み合わせます。
このような関係を、AはBに依存すると言います。AはBに依存していますが、Bから見たAはただのユーザーの1つであり、外部のクラスです。
カプセル化するということは、BはユーザーであるAなどの外部クラスにメソッドを公開して使えるようにはしますが、B自身の内部情報(処理の詳細、属性値)は外部に見えないよう隠蔽するということです。
属性のカプセル化の目的とは
属性のカプセル化の主な目的は、属性値を外部から不用意に変更されることを防ぐことにあります。
例として「自動車」というクラスを考えてみましょう。
自動車はアクセルを踏むと速度が上がり、ブレーキを踏むと速度が下がります。この点だけに注目して、「速度」という属性(単位はkm/時)と、「アクセルを踏む」、「ブレーキを踏む」という2つのメソッドがあるとします。
最初は速度=0の状態(インスタンス化した初期状態)です。
アクセルを踏むとある程度の速度まで徐々に上がります。
ブレーキを踏むと速度が徐々に下がり停止(速度=0)します。
運転手は「アクセルを踏む」、「ブレーキを踏む」というメソッドを使って速度を変更することができます。こうすることで急加速や急停止ができないように自動車が勝手にコントロールしてくれます。
ではもし仮に、運転手が速度を直接変更できたらどうなるでしょうか?
速度が0の状態から突然100になったら? 100から急に0になったら? 1000や-100になったら?
運転手や周りは無事ではすみませんし、自動車も壊れるでしょう。こういったことを防ぐために、速度の変更はメソッド内で行い、外部からは直接変更できないようにします。
ただし、運転手も現在の速度を知る必要はあります。このような場合のため、属性を「値の取得だけ可能」に設定することができます。
他にも、「値の変更だけ可能」、「取得と変更の両方可能」、「取得と変更の両方不可」という設定ができます。属性ごとにこれらの設定を適切にし、想定外の事態を防ぎます。これが属性のカプセル化の目的です。
メソッドのカプセル化の目的とは
メソッドのカプセル化の目的は、呼び出し側に処理の詳細を意識させないことです。
先ほどの自動車の例だと、運転手(呼び出し側)は「アクセルを踏む」だけで速度が上がることを知っています。この時、自動車の内部でどのように速度を上げているかを知る必要はありません。速度が上がるという結果が得られればそれでいいわけです。
実際の自動車にはガソリン自動車や電気自動車、ハイブリッド自動車など色々あり、自動車内部の仕組みは異なります。それでも、「アクセルを踏む」ことで速度が上がることは変わらないので、運転手はどの自動車でも運転できるわけです。
逆に自動車側から考えると、メーカーはエネルギー効率やパワーの向上のために内部の仕組みを変更することがあります。それでも、それまでと同じ様に「アクセルを踏む」ことで速度が上がることを保証できれば問題ないわけです。
このように、呼び出し側が知る必要のない内部処理の詳細を意識させないこと、逆に、内部処理の変更を呼び出し側に意識させないことが、メソッドのカプセル化の目的です。
まとめ
カプセル化とは、クラスの内部情報を隠蔽すること。その目的は3つ。
不用意な属性値の変更による想定外の事態を防ぐ。
呼び出し側が知る必要がない、内部処理の詳細を意識させない。言い換えれば、簡単に使えるようにするということ。
内部処理の変更を呼び出し側に意識させない。言い換えれば、同じ結果が保証できれば内部処理は変更しても良いということ。
補足:カプセル化=アクセサの利用?
カプセル化の説明で良く見かけるものとして、「フィールドをprivateにして、アクセサを用意しろ」というものがあります。
これはJavaの解説で特に良く見られます。アクセサとはゲッターやセッターと言われる、属性(Javaではフィールド)の値を外部から取得、変更するためのメソッドの総称です。C#などではプロパティと呼ばれます。
「private(自分以外は見えない)」はアクセス修飾子というものの1つで、属性は「取得と変更の両方不可」にしろという意味です。しかしながら、これはカプセル化のごく一部であり、今回の記事で言えば、属性のカプセル化の部分です。説明としてはあまりに不十分です。
さらに、これらの説明にありがちな問題として、全ての属性にアクセサを作るよう説明している点です。
本来は属性ごとに「ゲッターのみ」、「セッターのみ」、「両方あり」、「両方なし」を決めるべきですが、全ての属性について「両方あり」ではほとんど意味がありません(全く意味がないとは言いません)。また、アクセス修飾子についても全て「public」(誰でも使える)にしていて、他のアクセス修飾子について説明していないものは最悪です。
しっかりとカプセル化の目的を理解して、この様な説明に惑わされないようにしましょう。
アクセス修飾子やアクセサ、プロパティについては後日、【実践編】で詳しく説明します。
この記事へのコメントはありません。