カプセル化
出典: フリー百科事典『ウィキペディア(Wikipedia)』
カプセル化(カプセルか、encapsulation)とは、オブジェクト指向を構成する概念の一つ。オブジェクト内部のデータを隠蔽したり(データ隠蔽)、オブジェクトの振る舞いを隠蔽したり、オブジェクトの実際の型を隠蔽したりすることをいう。データ隠蔽と勘違いされやすいが、データ隠蔽はカプセル化の具体例の1つにすぎず、同一のものではない。
(やや人工的ではあるが)データ隠蔽の例として、色を表すオブジェクトを考えてみる。
カプセル化の第一の利点は変更に対する耐久性である。いま色の内部表現がRGB(光の三原色)で保持されているとして、これが何らかの都合でCMYK(色の三原色)に変更されたとする。外部のプログラムがデータ内部に直接アクセスを行っていた場合、このデータにアクセスしていたすべての箇所を同時に変更しなければならない。しかし公開メソッドを用いていれば、変更は内部表現から外部表現への公開メソッド内のみで済み、変更の影響を局所にとどめる事ができる。
第二の利点は概念の抽象化である。そもそも「色」という概念にとって、その内部表現がRGBであるかCMYKであるかは主要な問題ではなく、必要なら望みの形式がとりだせる抽象的な「色」であることが望ましい。加えて、その他の表現形式が追加されたとしても「色」の意味は変化するべきではない。このように、できるだけ形式と意味を分離する手段としてカプセル化は有効である。
[編集] 例
カプセル化の例をJava言語を用いて説明する。
以下のようなクラスがあったとき、
class NonEncapsulatedClass { public int x; public NonEncapsulatedClass(){ x = 100; } public int getX(){ return x; } }
このクラスを外部から利用するには
NonEncapsulatedClass nec = new NonEncapsulatedClass();
とすることでインスタンスを生成し、
System.out.println(nec.x);
とすることでNonEncapsulatedClass
クラスのpublic
なフィールドx
にアクセスできコンソールに実行結果として100
と表示することができる。 また、getX()
メソッドを使って
System.out.println(nec.getX());
とすることでもフィールドx
にアクセスし同じ実行結果を返すことができる。 また、 public
な変数なため当然、
nec.x = -20; System.out.println(nec.x);
とすることでフィールド値を100
から-20
に変えて表示することもできる。
このクラスはフィールド変数x
がpublic
になっているため簡単にx
にアクセスでき、 簡単にデータを変えることができてしまい、カプセル化されていない。
ここで上記のクラスを以下のように変更すると
public final class EncapsulatedClass { private int x; public NonEncapsulatedClass(){ x = 100; } public int getX(){ return x; } public void setX(int x) { if(x < 0){ throw new ArithmeticException("負の値は入力しないでください。"); } else if( x > 200){ throw new ArithmeticException("このクラスは200より大きな値はサポートしていません。"); } else { this.x = x; } } }
このクラスを他のクラスから呼び出すとき
System.out.println(nec.x);
としただけでコンパイルエラーが発生する。フィールド変数x
はアクセス権がprivate
なので 同一クラス内からしかアクセスできない。それに違反しているためこの時点でコンパイルエラーとなる。
ここではgetX()
メソッドを使って間接的にしかフィールド変数にアクセスすることができない。
System.out.println(nec.getX());
このx
を以下のようにして変更しようとすると、
nec.x = -20;
この時点でもコンパイルエラーが発生する。 ここでフィールド変数x
を変更するには、フィールド変数はprivate
になっており、 クラスの修飾子にはfinalがついているため継承が禁止されておりサブクラスからフィールド変数にアクセスすることもできない。 ここではsetX(int x)
メソッドを使わなくてはx
にアクセスしてxの値を変更することはできない。 では、 ここでsetX(int x)
を以下のように実行したらどうなろうだろうか。
nec.setX(-20);
プログラムソースコードのコンパイルは通る。しかし実行時に ArithmeticException
例外が生じてプログラムが終了してしまうだろう。 なぜならそのようにプログラムされているからだ。 同様に
nec.setX(201);
としてもArithmeticException
例外が生じて終了してしまうだろう。 このようにフィールド変数xに代入できる数値範囲を計器やバルブの調節ツマミの安全弁のように限定したいとき、 安全のため、セキュリティのため、不用意にこの変数に特定の値を入れたくないときカプセル化は役立つのである。
このようなカプセル化を実現する手法や構文にアクセサ、プロパティなどが存在する。