この記事では、オブジェクト指向プログラミングの重要な概念であるカプセル化について理解することができます。カプセル化の基本概念を解説し、学生情報の管理と銀行口座の管理という2つの実践的なプログラム例を通じて、その適用方法を学びます。
はじめに
この記事のコードをコピペしてEclipseで出力結果を確認してみよう!
カプセル化の基本
カプセル化とは、クラスの内部データ(フィールド)を外部から直接アクセスできないようにし、代わりにメソッドを通じてアクセスする仕組みです。これにより、データの整合性を保ち、クラスの実装詳細を隠蔽することができます。
カプセル化の主な特徴は以下の通りです:
- フィールドをprivateにする
- フィールドにアクセスするためのpublicなゲッター(getter)とセッター(setter)メソッドを提供する
- 必要に応じてゲッターやセッター内でデータの検証や加工を行う
プログラム例1: 学生情報の管理
Student.java
public class Student {
// privateフィールド
private String name;
private int age;
// コンストラクタ
public Student(String name, int age) {
this.name = name;
setAge(age); // セッターを使用して年齢を設定
}
// 名前のゲッター
public String getName() {
return name;
}
// 名前のセッター
public void setName(String name) {
this.name = name;
}
// 年齢のゲッター
public int getAge() {
return age;
}
// 年齢のセッター(値の検証あり)
public void setAge(int age) {
if (age >= 0 && age <= 120) {
this.age = age;
} else {
System.out.println("無効な年齢です。");
}
}
}
Main.java
public class Main {
public static void main(String[] args) {
// Studentオブジェクトの作成
Student student1 = new Student("山田太郎", 20);
Student student2 = new Student("佐藤花子", 22);
// 学生情報の表示
System.out.println("学生1の情報:");
displayStudentInfo(student1);
System.out.println("\n学生2の情報:");
displayStudentInfo(student2);
// 学生情報の更新
student1.setName("山田次郎");
student1.setAge(21);
System.out.println("\n更新後の学生1の情報:");
displayStudentInfo(student1);
// 無効な年齢でのテスト
student2.setAge(150);
}
// 学生情報を表示するメソッド
private static void displayStudentInfo(Student student) {
System.out.println("名前: " + student.getName());
System.out.println("年齢: " + student.getAge());
}
}
出力結果:
学生1の情報:
名前: 山田太郎
年齢: 20
学生2の情報:
名前: 佐藤花子
年齢: 22
更新後の学生1の情報:
名前: 山田次郎
年齢: 21
無効な年齢です。
Student.javaの解説
- クラス定義
public class Student {
// ...
}
Student
という名前の公開クラスを定義しています。
- プライベートフィールド
private String name;
private String age;
クラス内でprivate
キーワードを使用して、name
とage
フィールドを定義しています。これらのフィールドは直接外部からアクセスできません。
- コンストラクタ
public Student(String name, int age) {
this.name = name;
setAge(age); // セッターを使用して年齢を設定
}
Student
クラスのコンストラクタを定義しています。name
は直接設定し、age
はセッターメソッドを通して設定しています。
- 名前のゲッター
public String getName() {
return name;
}
name
フィールドの値を取得するためのゲッターメソッドです。
- 名前のセッター
public void setName(String name) {
this.name = name;
}
name
フィールドの値を設定するためのセッターメソッドです。
- 年齢のゲッター
public int getAge() {
return age;
}
age
フィールドの値を取得するためのゲッターメソッドです。
- 年齢のセッター(値の検証あり)
public void setAge(int age) {
if (age >= 0 && age <= 120) {
this.age = age;
} else {
System.out.println("無効な年齢です。");
}
}
age
フィールドの値を設定するためのセッターメソッドです。このメソッドには値の検証ロジックが含まれており、年齢が0から120の範囲内にある場合のみ値を設定します。
このコードは、Javaにおけるカプセル化の基本的な実装を示しています:
- プライベートフィールド: クラス外部からの直接アクセスを防ぎます。
- パブリックなゲッターとセッター: フィールドへの制御されたアクセスを提供します。
- 値の検証: セッターメソッド内で入力値を検証し、不適切な値の設定を防ぎます。
このアプローチにより、クラスの内部データを保護し、データの整合性を維持することができます。また、将来的にクラスの内部実装を変更する際にも、外部のコードに影響を与えずに変更を行うことができます。
Main.javaの解説
- クラス定義
public class Main {
// ...
}
Main
という名前の公開クラスを定義しています。
- main メソッド
public static void main(String[] args) {
// ...
}
これはプログラムのエントリーポイントです。
- Student オブジェクトの作成
Student student1 = new Student("山田太郎", 20);
Student student2 = new Student("佐藤花子", 22);
Student
クラスのコンストラクタを使用して、2つの Student
オブジェクトを作成しています。
- 学生情報の表示
System.out.println("学生1の情報:");
displayStudentInfo(student1);
System.out.println("\n学生2の情報:");
displayStudentInfo(student2);
displayStudentInfo
メソッドを呼び出して、各学生の情報を表示しています。
- 学生情報の更新
student1.setName("山田次郎");
student1.setAge(21);
System.out.println("\n更新後の学生1の情報:");
displayStudentInfo(student1);
setName
と setAge
メソッドを使用して student1
の情報を更新し、再度表示しています。
- 無効な年齢でのテスト
student2.setAge(150);
無効な年齢を設定しようとしています。これは Student
クラスの setAge
メソッド内で処理されるはずです。
- displayStudentInfo メソッド
private static void displayStudentInfo(Student student) {
System.out.println("名前: " + student.getName());
System.out.println("年齢: " + student.getAge());
}
このプライベートメソッドは、Student
オブジェクトの情報を表示するために使用されます。getName
と getAge
メソッドを呼び出しています。
このコードは、Student
クラスの使用例を示しています:
- オブジェクトの作成と初期化
- ゲッターメソッドを使用した情報の取得
- セッターメソッドを使用した情報の更新
- 無効なデータ(年齢)の処理
このコードは、オブジェクト指向プログラミングの基本的な概念(カプセル化、メソッドの使用)を実践しています。また、displayStudentInfo
メソッドの使用は、コードの再利用性を高めています。
プログラム例2: 銀行口座の管理
BankAccount.java
public class BankAccount {
// privateフィールド
private String accountNumber;
private double balance;
// コンストラクタ
public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}
// 口座番号のゲッター
public String getAccountNumber() {
return accountNumber;
}
// 残高のゲッター
public double getBalance() {
return balance;
}
// 入金メソッド
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println(amount + "円入金しました。");
} else {
System.out.println("無効な入金額です。");
}
}
// 出金メソッド
public void withdraw(double amount) {
if (amount > 0 && balance >= amount) {
balance -= amount;
System.out.println(amount + "円出金しました。");
} else {
System.out.println("出金できません。");
}
}
}
Main.java
public class Main {
public static void main(String[] args) {
// BankAccountオブジェクトの作成
BankAccount account1 = new BankAccount("1234-5678", 10000);
BankAccount account2 = new BankAccount("8765-4321", 20000);
// 口座情報の表示
System.out.println("口座1の情報:");
displayAccountInfo(account1);
System.out.println("\n口座2の情報:");
displayAccountInfo(account2);
// 入金と出金の操作
System.out.println("\n口座1での操作:");
account1.deposit(5000);
account1.withdraw(2000);
account1.withdraw(20000); // 残高不足のケース
System.out.println("\n操作後の口座1の情報:");
displayAccountInfo(account1);
System.out.println("\n口座2での操作:");
account2.deposit(-1000); // 無効な入金額のケース
account2.deposit(10000);
account2.withdraw(5000);
System.out.println("\n操作後の口座2の情報:");
displayAccountInfo(account2);
}
// 口座情報を表示するメソッド
private static void displayAccountInfo(BankAccount account) {
System.out.println("口座番号: " + account.getAccountNumber());
System.out.println("残高: " + account.getBalance() + "円");
}
}
出力結果:
口座1の情報:
口座番号: 1234-5678
残高: 10000.0円
口座2の情報:
口座番号: 8765-4321
残高: 20000.0円
口座1での操作:
5000.0円入金しました。
2000.0円出金しました。
出金できません。
操作後の口座1の情報:
口座番号: 1234-5678
残高: 13000.0円
口座2での操作:
無効な入金額です。
10000.0円入金しました。
5000.0円出金しました。
操作後の口座2の情報:
口座番号: 8765-4321
残高: 25000.0円
BankAccount.javaの解説
- クラス定義
public class BankAccount {
// ...
}
BankAccount
という名前の公開クラスを定義しています。
- プライベートフィールド
private String accountNumber;
private double balance;
クラス内でprivate
キーワードを使用して、accountNumber
とbalance
フィールドを定義しています。これらのフィールドは直接外部からアクセスできません。
- コンストラクタ
public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}
BankAccount
クラスのコンストラクタを定義しています。口座番号と初期残高を受け取り、フィールドを初期化します。
- 口座番号のゲッター
public String getAccountNumber() {
return accountNumber;
}
accountNumber
フィールドの値を取得するためのゲッターメソッドです。
- 残高のゲッター
public double getBalance() {
return balance;
}
balance
フィールドの値を取得するためのゲッターメソッドです。
- 入金メソッド
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println(amount + "円入金しました。");
} else {
System.out.println("無効な入金額です。");
}
}
このメソッドは入金処理を行います。入金額が正の値である場合のみ残高を更新し、そうでない場合はエラーメッセージを表示します。
- 出金メソッド
public void withdraw(double amount) {
if (amount > 0 && balance >= amount) {
balance -= amount;
System.out.println(amount + "円出金しました。");
} else {
System.out.println("出金できません。");
}
}
このメソッドは出金処理を行います。出金額が正の値で、かつ残高が十分にある場合のみ残高を更新し、そうでない場合はエラーメッセージを表示します。
このコードは、銀行口座を模したクラスの基本的な実装を示しています:
- カプセル化: プライベートフィールドとパブリックメソッドを使用してデータを保護しています。
- データの整合性: 入金と出金メソッドで値のチェックを行い、不正な操作を防いでいます。
- 情報の隠蔽: 残高の直接操作はできず、適切なメソッドを通してのみ変更可能です。
このアプローチにより、銀行口座の基本的な機能を安全に実装し、不正な操作や誤った状態の発生を防ぐことができます。また、将来的に追加機能(例:利息計算、取引履歴など)を実装する際にも、既存のコードに影響を与えずに拡張することができます。
Main.javaの解説
- クラス定義
public class Main {
// ...
}
Main
という名前の公開クラスを定義しています。
- main メソッド
public static void main(String[] args) {
// ...
}
これはプログラムのエントリーポイントです。
- BankAccount オブジェクトの作成
BankAccount account1 = new BankAccount("1234-5678", 10000);
BankAccount account2 = new BankAccount("8765-4321", 20000);
BankAccount
クラスのコンストラクタを使用して、2つの口座オブジェクトを作成しています。
- 口座情報の表示
System.out.println("口座1の情報:");
displayAccountInfo(account1);
System.out.println("\n口座2の情報:");
displayAccountInfo(account2);
displayAccountInfo
メソッドを呼び出して、各口座の情報を表示しています。
- 入金と出金の操作
System.out.println("\n口座1での操作:");
account1.deposit(5000);
account1.withdraw(2000);
account1.withdraw(20000); // 残高不足のケース
System.out.println("\n口座2での操作:");
account2.deposit(-1000); // 無効な入金額のケース
account2.deposit(10000);
account2.withdraw(5000);
各口座に対して入金と出金の操作を行っています。意図的に無効な操作(残高不足の出金、負の入金額)も含めています。
- 操作後の口座情報表示
System.out.println("\n操作後の口座1の情報:");
displayAccountInfo(account1);
System.out.println("\n操作後の口座2の情報:");
displayAccountInfo(account2);
操作後の各口座の情報を再度表示しています。
- displayAccountInfo メソッド
private static void displayAccountInfo(BankAccount account) {
System.out.println("口座番号: " + account.getAccountNumber());
System.out.println("残高: " + account.getBalance() + "円");
}
このプライベートメソッドは、BankAccount
オブジェクトの情報を表示するために使用されます。getAccountNumber
と getBalance
メソッドを呼び出しています。
このコードは、BankAccount
クラスの使用例を示しています:
- オブジェクトの作成と初期化
- ゲッターメソッドを使用した情報の取得
- 入金(
deposit
)と出金(withdraw
)メソッドの使用 - 無効な操作(残高不足の出金、負の入金額)のテスト
このコードは、オブジェクト指向プログラミングの基本的な概念(カプセル化、メソッドの使用)を実践しています。また、displayAccountInfo
メソッドの使用は、コードの再利用性を高めています。このプログラムは、BankAccount
クラスの機能が正しく動作していることを確認するためのテストケースとしても機能しています。
まとめ
- カプセル化は、データ(属性)と、そのデータを操作するメソッド(振る舞い)を一つのユニット(クラス)にまとめる概念です。
- プログラム例では、アクセス修飾子とゲッターとセッターを使用して、情報をカプセル化し、不正な操作を防いでいます。
- カプセル化により、データの整合性が保たれ、オブジェクトの状態を制御することが可能になります。
カプセル化を適切に実装することで、より安全で保守性の高いコードを作成することができます。これは特に大規模なプロジェクトや長期的なメンテナンスが必要なシステムにおいて重要です。プログラマーはカプセル化の概念を十分に理解し、適切に適用することで、より堅牢で拡張性のあるソフトウェアを設計することができます。
コメント