スッキリわかるJava入門 第10章 カプセル化③
第10章 カプセル化③
getter/setterの存在価値
- Heroクラスのnameフィールドのカプセル化前後。
// カプセル化を行う前 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つのソースファイルに複数宣言してもよい。
カプセル化を支えている考え方
メソッドでフィールドを保護する
- 「外部から直接触られないよう、メソッドという殻(カプセル)によってフィールドが保護されている」ように見える事から、カプセル化という名前が付いている。
- なぜカプセル化ではメソッドではなくフィールドを保護しようとするのか?それは、メソッドよりフィールドの方が異常な状態(不具合)になりやすいから。
- メソッドの処理内容は、プログラミング段階で決定し、一度コンパイルされればプログラム実行中に変化することはない。
- フィールドの中身は、プログラムが動作する間に逐次、変化していく。動作中に異常な値になる危険性もある。結果的に不具合の多くは「フィールドに予期しない値が入る」という形で発現する。
- 「プログラムの不具合を減らすためには、メソッドよりもフィールドを保護する事が重要」。