Javaのようなオブジェクト指向言語では、特徴やメリットとして「カプセル化」の機能が挙げられます。
本記事では、Javaのカプセル化にフォーカスして、概要や使い方をご紹介していきます。
Javaのカプセル化とは
Javaのカプセル化は、オブジェクト指向言語の性質として、データを保護するために利用する考え方です。
カプセル化とは
カプセル化は、アクセス修飾子を適切に設定することで、「フィールド」や「メソッド」へ外部プログラムからのアクセスを制限するために利用されます。
クラスをカプセル化することにより、クラス毎の独立性が高まり、想定しない操作をされないよう制御することが可能です。
カプセル化のメリット
カプセル化を利用するメリットは、意図しないアクセスを防ぐことにより未然にバグを防いだり、セキュリティ面の強化に繋がります。
また、外部から利用する際にも、提供されたメソッドを利用すれば良いだけであり内部構造を理解する必要がなくなります。
カプセル化のデメリット
一方でカプセル化のデメリットとしては、ソースコードの記述量が増える点にあります。
またクラスの意図を理解していないと、修正によりカプセル化のメリットを壊してしまう可能性も否定出来ません。
Javaカプセル化の基本
Javaのカプセル化といえば、ゲッター(getter)とセッター(setter)の存在が挙げられます。
簡単に使い方と役割を確認しておきましょう。
基本的な考え方
カプセル化の基本的な考え方として、フィールドのアクセス修飾子を「private」に指定し、メソッドを「public」として定義します。
フィールド変数の値を変更するためのメソッドとして、ゲッターとセッターと呼ばれるpublic修飾子のメソッドを用意する方法が一般的です。
ゲッター(getter)
ゲッターは、フィールド変数に格納された値を取得するために利用されるメソッドです。
ゲッターは一般的に「getフィールド名」という名前で定義します。
EclipseのようなIDEでは自動生成されるような機能も利用可能で、実際に作成すると下記のようなコードになります。
private String name; public String getName() { return name; }
フィールド変数をprivateで定義して、実際にアクセスする場合「getNmae」メソッドを経由する必要があります。
セッター(setter)
セッターは、フィールド変数に値を設定するために利用されるメソッドです。
ゲッターは一般的に「setフィールド名」という名前で定義します。
ゲッターとセッターは基本的にセットで定義されます。
private String name; public void setName(String name) { this.name = name; }
カプセル化のJavaサンプルコード
実際にいくつかのパターンでJavaのカプセル化についてもう少し詳しく確認していきましょう。
初期値からの変更不可
例えば初期値で設定した値を変更させたくない場合、コンストラクタでのみフィールド値を設定出来るようなクラスを作成することが出来ます。
public class Main { public static void main(String[] args) { Human human = new Human("山田 太郎", 25); // human.name = "佐藤 太郎"; private修飾子なので不可 human.setName("佐藤 太郎"); // human.age = 30; private修飾子なので不可 // human.setAge(30); setAgeが定義されていないので不可 System.out.println("名前: " + human.getName() + ", 年齢: " + human.getAge()); } } class Human{ private String name; private int age; Human(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } }
実行結果が下記です。
名前: 佐藤 太郎, 年齢: 25
サンプルではコンストラクタでは初期値としてフィールドに値を設定出来ますが、ageフィールドはセッターが用意されていないため、その後変更することが出来ない仕様となっています。
ただしageフィールドもゲッターは定義されているため、外部から値を取得することは可能です。
文字数チェック
次に値を設定する際、文字数チェックを行うセッターを定義してみましょう。
public class Main { public static void main(String[] args) { Human human = new Human("山田太郎", 25); human.setName("山田親太朗"); human.setName("佐藤太郎"); } } class Human{ private String name; private int age; Human(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { if(name.length() < 5) { this.name = name; System.out.println("名前を" + name + "に変更しました。"); } else { System.out.println("文字数が多すぎます。"); } } }
実行結果が下記です。
文字数が多すぎます。 名前を佐藤太郎に変更しました。
23~31行目に定義したセッターで、文字数をチェックし4文字よりも大きい場合には値の設定を実施しないように制御しています。
ブラックボックス化
カプセル化を実施することにより、ブラックボックス化となっている処理の例も確認してみましょう。
public class Main { public static void main(String[] args) { Human human = new Human("山田太郎", 25); human.introduce(); } } class Human{ private String name; private int age; Human(String name, int age) { this.name = name; this.age = age; } void introduce() { System.out.println("名前は" + this.name + ", 年齢は" + this.age + "歳です。"); } }
実行結果は下記です。
名前は山田太郎, 年齢は25歳です。
呼び出し側であるMainメソッドではHumanクラスのintroduceメソッドを呼び出しているだけです。
つまりHumanクラスのintroduceメソッドの処理内容が今後変更されたとしても、呼び出し元では特に修正を加える必要がありません。
例えば、自己紹介で年齢の出力を止めようとなった場合、Humanクラスのintroduceメソッドの処理を下記のように変更するだけです。
public class Main { public static void main(String[] args) { Human human = new Human("山田太郎", 25); human.introduce(); } } class Human{ private String name; private int age; Human(String name, int age) { this.name = name; this.age = age; } void introduce() { System.out.println("名前は" + this.name + "です。"); } }
実行結果が下記です。
名前は山田太郎です。
さいごに: Javaシステム開発ではカプセル化を活用しよう
本記事では、Javaのカプセル化について、基本情報から使い方までをご紹介してきました。
Javaのようなオブジェクト指向言語では「カプセル化」「継承」「ポリモーフィズム」の3つの概念への理解が重要です。
まずは今回ご紹介したカプセル化の考え方を把握して、Java(オブジェクト指向言語)らしいプログラム開発が出来るよう学習していきましょう。
サンプルの場合ゲッターもセッターもフィールドに直接アクセスしているのと変わらない処理内容となっていますが、メソッドに条件を追加していくことでアクセス制御が可能となります。