カプセル化
カプセル化(カプセルか、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 EncapsulatedClass(){ 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に代入できる数値範囲を計器やバルブの調節ツマミの安全弁のように限定したいとき、安全のため、セキュリティのため、不用意にこの変数に特定の値を入れたくないときカプセル化は役立つ。
このようなカプセル化を実現する手法や構文にアクセサ、プロパティなどが存在する。