パパの勉強部屋

勉強の記録をつけています。Java、ネットワーク、Excel、etc.

スッキリわかるJava入門 第10章 カプセル化③

第10章 カプセル化

getter/setterの存在価値

// カプセル化を行う前
public class Hero {
	String name;
}

// カプセル化を行った後
public class Hero {
	private String name;

	public String getName(){
		return this.name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
}
メリット1:Read Only、Write Onlyのフィールドを実現できる
  • setName()メソッドを削除すれば、外部から読めるが書き換えられない(Read Only)フィールドにできる。よく多用されるテクニック。
  • getName()メソッドを削除すれば、外部から自由に書き換えできるが、読めない(Write Only)フィールドにできる。あまり使われない。
メリット2:フィールドの名前など、クラスの内部設計を自由に変更できる
  • たとえば、何らかの理由でnameというフィールド名をnewNameに変更したい場合。
  • getter/setterを準備せず、他のクラスからnameフィールドを直接読み書きしていた場合、他のクラスすべての開発者にアクセスするフィールド名を変更してもらう必要がある。
  • nameフィールドを隠し、外部からはgetter/setter経由で読み書きさせるなら、フィールド名の変更は自由。getter/setterの中身でフィールド名を使っている箇所だけ修正すれば良い。
メリット3:フィールドへのアクセスを検査できる
  • クラス外部からnameフィールドの値を書き換えたい場合、setterを使う必要がある=setterを実行せずに、nameフィールドを書き換える事は不可能。
  • これを利用し、setterで「設定されようとしている値が妥当かを検査する」こともJavaプログラミングの定石。
  • 以下のsetName()メソッドは、nameフィールドへの値を変更しようとするたびに検査を行う。

public class Hero {
	private String name;

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		// 代入前に、代入しようとしている値が妥当かを検査する
		if (name == null) { // nullが設定されそうになった!
			throw new IllegalArgumentException("名前にnullが設定されそうになりました。処理を中断します。");
		}
		if (name.length() <= 1) { // 文字列長が異常(短すぎる)
			throw new IllegalArgumentException(
					"1文字以下の名前が設定されそうになりました。処理を中断します。");
		}
		if (name.length() >= 8) { // 文字列長が異常(長すぎる)
			throw new IllegalArgumentException(
					"8文字以上の名前が設定されそうになりました。処理を中断します。");
		}
		this.name = name; // 検査完了!代入しても大丈夫。
	}
}

クラスに対するアクセス制御

2つのアクセス制御レベル
名前 Javaでの記述 許可する範囲 制限
package private (何も書かない) 自分と同じパッケージに属するクラス 厳しい
public public すべてのクラス 緩い
  • クラス宣言の前にはpublicをつけると丸暗記していたが、何も書かない場合、そのクラスは同一パッケージに属するクラスからのアクセスのみ許可される。
  • 他のパッケージに属するクラスからのアクセスが禁止される。イメージとしては「他のパッケージに属するクラスから、そのクラスの存在自体が見えなくなる」と捉えた方がよい。

非publicクラスとソースファイル

  • 別パッケージのクラスから見えない代わりに、publicクラスでは許可されない次の2つが許可されている。
  • ①クラスの名前はソースファイル名と異なってもよい。
  • ②1つのソースファイルに複数宣言してもよい。

カプセル化を支えている考え方

メソッドでフィールドを保護する
  • 「外部から直接触られないよう、メソッドという殻(カプセル)によってフィールドが保護されている」ように見える事から、カプセル化という名前が付いている。
  • なぜカプセル化ではメソッドではなくフィールドを保護しようとするのか?それは、メソッドよりフィールドの方が異常な状態(不具合)になりやすいから。
  • メソッドの処理内容は、プログラミング段階で決定し、一度コンパイルされればプログラム実行中に変化することはない。
  • フィールドの中身は、プログラムが動作する間に逐次、変化していく。動作中に異常な値になる危険性もある。結果的に不具合の多くは「フィールドに予期しない値が入る」という形で発現する。
  • 「プログラムの不具合を減らすためには、メソッドよりもフィールドを保護する事が重要」。
カプセル化の本質
  • 不具合とは:そもそもバグとは、現実世界と仮想世界が食い違ってしまうこと。
  • カプセル化を使えば、どのように利用されてもフィールドに不正な値が入ってしまうことがない「現実の登場人物と矛盾することがないクラス」を作ることができる。
  • 「現実の登場人物と矛盾することがないクラス」を集めてプログラムを作れば、「現実世界と矛盾することがないプログラム」になるという考えがカプセル化の本当の狙い。