はじめに
こんにちは。
プログラミング初心者Wakinozaと申します。
Java勉強中に調べたことを記事にまとめています。
十分気をつけて執筆していますが、なにぶん初心者が書いた記事なので、理解が浅い点などあるかと思います。
記事を参考にされる方は、初心者の記事であることを念頭において、お読みいただけると幸いです。
間違い等あれば、指摘いただけると助かります。
対象読者
- Javaを勉強中の方
- Java SE Bronze試験を勉強中の方
- Javaのカプセル化・データ隠蔽ついてざっくり知りたい方
目次
1. 変更に強い設計とは
2. カプセル化
3. データ隠蔽
4. アクセサメソッド
5. java SE Bronze試験対策の補足
本文
1. 変更に強い設計とは
ソフトウェア開発において「設計」とは、「開発・保守作業の効率化」と「コストカット」を実現するための重要な作業です。
では、「良い設計」とはどんな設計でしょう。
諸説ありますが、「変更に強い」という要素が重要となってきます。
ソフトウェア開発は、作れば終わりというものではありません。
リリース後も、不具合の修正や仕様変更など、長期間にわたって変更が必要となります。
もし、変更を考慮しない設計だった場合、どこを変更すれば良いのか、変更範囲はどこまでなのかを把握することが難しくなり、変更の度に膨大な時間とコストがかかります。
コスト増大を未然に防ぐため、設計の段階から「変更に強い」ソフトウエアを意識しなければなりません。
では、「変更に強い設計」とはどういったものでしょうか。
こちらも諸説ありますが、以下の2つの条件を満たすものが「変更に強い設計」と言われます。
- 変更発生時に、その影響範囲がすぐに特定できること
- 変更への対応が工数をかけずにできること
まず、変更が発生したときに、影響範囲をすぐに特定できることが必要です。変更したい項目がどこに記述されているかが一目で分からないと、変更箇所を特定するためにコードを1つ1つ確認する羽目になります。変更箇所が複数の場所に散っていれば、変更漏れのなどの原因にもなります。そのため、どこに何か記述されているのか一目でわかるように、関連項目をまとめておくことが求められます。
また、変更への対応が工数をかけずにできることも必要です。変更する場合、対象になる部分だけでなく、対象を利用する部分も変更しなければなりません。しかし、Aを変更したからBを変更して、またBを変更したからCを変更して、と変更箇所が次々と広がってしまうような設計では、変更に強いと言えません。そのため、変更の影響範囲を明確に区切れる設計が求められます。
そういった変更に強いソフトウェアの設計するための原則の1つが、「カプセル化」です。
2. カプセル化
カプセル化は、コードの影響範囲特定に関わる重要な設計原則の一つです。
カプセル化とは、関連するフィールド値とそのフィール値を必要とするメソッドをまとめて、1つのモジュールとして定義することです。適切にカプセル化されていれば、変更箇所がどのモジュールか特定しやすくなり、変更に強い設計となります。
例として、以下のコードをご覧ください。
public class Student {
String familyName;
String lastName;
String studentId;
String teacherName;
String schoolName;
public String getStudentName(){
//any code
}
public String getSchoolName(){
//any code
}
}
Studentクラスにフィールドやメソッドがまとめてあります。このクラスをカプセル化の観点から見ていきましょう。
カプセル化の考えでは、関連するフィールド値とフィールド値を使用するメソッドを一つのモジュールにまとめる必要があります。
フィールドを見ると、Studentクラスでありながら、「先生の名前」や「学校名」まで含まれています。Studentに関連がないフィールドはTeacherクラスやschoolクラスなど別のクラスを作り、そちらに移したほうが良いでしょう。
また、メソッドを見ると、Studentクラスに関係のないgetSchoolNameメソッドが入っています。こちらも、Teacherクラスなどに移したほうが良いでしょう。
関連のないフィールドやメソッドを他クラスに移す事によって、Studentクラスは、Studentに関連するフィールドとメソッドだけを扱えば良い状態になり、クラスの役割が単純化されました。その上、クラスの役割が単純化されたことで、今後Studentに関連する変更があるときはまずStudentクラスを確認するというように、変更箇所を把握することも容易になります。
カプセル化を意識することで、クラスの役割が単純化され、変更箇所を把握しやすくなるのです。
3. データ隠蔽
カプセル化で、関係するデータとそのデータを必要とするメソッドをまとめました。これによって、フィールド値を必要とするメソッドも原則として同じモジュール内にある状態となり、変更範囲の把握が容易になりました。
しかしもし、フィールド値が他のクラスからもアクセスされていれば、変更の影響範囲は広がります。カプセル化の原則が崩れ、変更に弱い設計となってしまいます。
カプセル化を実現し、変更に強い設計を実現するための具体的な方法として、「データ隠蔽」があります。
「データ隠蔽」とは、アクセス修飾子によって、クラス外部からのアクセスを制限することです。
カプセル化を崩す要因は、あるモジュールに他のモジュールがアクセスできることにあります。それを防ぐため、アクセス修飾子によって他のクラスからのアクセスを制限し、データを隠蔽するのです。
アクセス修飾子は、以下の4種類があります。
名称 | 指定方法 | アクセスを許可する範囲 |
---|---|---|
private | private | 自分のクラスのみ |
package private | 何も書かない | 同じパッケージのクラスのみ |
protected | protected | 同じパッケージのクラスか自分を継承した子クラスのみ |
public | public | すべてのクラス |
publicの制限が最も緩く、privateの制限が最も厳しいです。
フィールド・メソッド・コンストラクタを宣言する際に、上の4種類のアクセス修飾子を記載することで、公開範囲を制限できます。
ちなみに、「アクセス修飾子なし」はpackage privateという制限レベルを意味します。「何も書かないpackage private」の方が「protected」より制限が厳しい点は、直感に反するため注意が必要です。
クラスのアクセス修飾子は、「アクセス修飾子なしのpackage private」と「public」の2種類です
カプセル化の維持のため、フィールドは原則「private」とするのが望ましいです。メソッドは「public」を原則とし、必要な場合のみ公開範囲を制限するという運用が一般的です。
フィールドを「private」とすることで、他クラスからのフィールドにアクセスすることはできなくなりました。すなわち、フィールド値を利用できるのは、同じクラスのメソッドのみとなります。それは同時に、仮にフィールドを変更しても、変更範囲がクラス内に限定できるという事です。カプセル化が維持され、変更に強い設計となりました。
4. アクセサメソッド
しかし、データ隠蔽を行うと問題が発生します。
当たり前ですが、他クラスの値を利用するメソッドがフィールド値を取得できず、処理が実行できないのです。
この問題を解決するために用意されたのが、「アクセサメソッド」です。
「アクセサメソッド」とは、他のクラスからフィールド値を参照したり、書き換えたりするための専用メソッドです。フイールド値を参照するメソッドを「getter」、フィールド値を書き換えるメソッドを「setter」と言います。
せっかくアクセス修飾子でデータ隠蔽したのに、アクセサメソッドを作ったらデータ隠蔽の意味がないと思った方、全くもってその通りです。
アクセサメソッドは、データ隠蔽をした場合に必ず準備しなければならないものではありません。まずは、他クラスのフィールド値を必要とするメソッドを、フィールドと同じクラスにまとめることができないか再度確認することが必要です。同じモジュールにまとめてカプセル化できれば、アクセサメソッドは不要になります、
しかし、複数のクラスのフィールド値を必要とするメソッドなど、どうしても他クラスのフィールド値が必要な場合もあります。
その場合は、フィールドをprivateにした上で、アクセサメソッドを準備しましょう。
アクセサメソッドも、ただの「フィールド値の代わり」ではありません。
アクセサメソッドを正しく設定することで、フィールドに不正な値が上書きされないように監視したり、変更の影響範囲を狭めたりすることができます。
具体的なアクセサメソッドの利点は、以下の3つです。
- フィールドの公開範囲をコントロールできます。例えば、setter無しgetterのみとすることで、参照のみ可能で変更不可のフィールドに設定できます
- 変更範囲を極小化できます。例えば、後からフィールド名を変更しなければならないとします。アクセサメソッドがない場合は、プログラムで記述されているフィールド名すべてを新しいものに変更しなければならなくなります。変更範囲は広くなり、変更漏れなどのミスの温床にもなりかねません。しかし、アクセサメソッドがあれば、getterの仕様を変更するだけで対応でき、変更範囲をクラス内に収めることができます
- 不正な値の代入を防ぐ。setterに代入する値を検証するコードを記述することで、不正な値が上書きされるのを防ぐことができます
カプセル化を意識しながらアクセサメソッドを適時利用することで、変更に強い設計が可能になりるのです。
5. java SE Bronze試験対策の補足
書籍によっては、カプセル化=データ隠蔽としているものもありますが、java SE Bronze試験ではこれらを区別しています。
記事の用語を、試験問題を考慮してまとめます。
- 「カプセル化」は、関係するデータとデータを必要とする処理を1つのモジュールにまとめること。変更に強い設計をするために考えるべき原則の一つ
- 「データ隠蔽」は、フィールドにアクセス修飾子を記載し、公開範囲を限定すること。カプセル化を維持するための手段の一つ
- 「アクセサメソッド」は、他のクラスがフィールド値を参照・書き換えるためのメソッド。データ隠蔽にともなって必要とされるものであり、カプセル化とは直接関係ありません
まとめ
- 良い設計は、変更に強い設計である。変更に強い設計を実施するには、カプセル化で関連するものを1つのモジュールにまとめる必要がある
- カプセル化を維持するために、フィールドをprivateにして他のクラスからアクセスできないようデータ隠蔽を行う
- 必要な場合は、アクセサメソッドを準備する。しかし、安易にアクセサメソッドを作るのではなく、まずはカプセル化できないか再考すること
記事は以上です。
最後までお読みいただき、ありがとうございました。
参考文献
この記事は以下の情報を参考にして執筆しました。
- [徹底攻略 Java SE Bronze 問題集]
- [スッキリわかるJava入門 第4版]
- [10.1 カプセル化とアクセス修飾子(public、protected、private)~Java Basic編](最終更新 2023-11-05)(https://qiita.com/KenyaSaitoh/items/e3b423b1f7d95c4e9e7a) (参照 2025-04-13)