実践:OOP
このレッスンはPhase 3のハンズオン実践で、図書管理システムを通じてOOP知識を定着させます。
プロジェクト要件
図書管理システムを設計し、以下をサポート:
- 書籍情報管理(CRUD)
- 読者情報管理
- 書籍の貸出と返却
- 例外処理
クラス設計
エンティティクラス
JAVA
// Bookクラス
public class Book {
private String isbn;
private String title;
private String author;
private boolean borrowed;
public Book(String isbn, String title, String author) {
this.isbn = isbn;
this.title = title;
this.author = author;
this.borrowed = false;
}
// getter/setter
public String getIsbn() { return isbn; }
public String getTitle() { return title; }
public String getAuthor() { return author; }
public boolean isBorrowed() { return borrowed; }
public void setBorrowed(boolean borrowed) { this.borrowed = borrowed; }
@Override
public String toString() {
return String.format("[%s] %s - %s (%s)", isbn, title, author, borrowed ? "貸出中" : "貸出可能");
}
}
// Readerクラス
public class Reader {
private String id;
private String name;
private List<Book> borrowedBooks;
public Reader(String id, String name) {
this.id = id;
this.name = name;
this.borrowedBooks = new ArrayList<>();
}
public String getId() { return id; }
public String getName() { return name; }
public List<Book> getBorrowedBooks() { return borrowedBooks; }
public void borrowBook(Book book) {
borrowedBooks.add(book);
}
public void returnBook(Book book) {
borrowedBooks.remove(book);
}
@Override
public String toString() {
return name + " (ID:" + id + ", 貸出:" + borrowedBooks.size() + ")";
}
}
例外クラス
JAVA
// 書籍がすでに貸出中の例外
public class BookAlreadyBorrowedException extends Exception {
public BookAlreadyBorrowedException(String message) {
super(message);
}
}
// 書籍が貸出中でない例外
public class BookNotBorrowedException extends Exception {
public BookNotBorrowedException(String message) {
super(message);
}
}
// 読者が見つからない例外
public class ReaderNotFoundException extends Exception {
public ReaderNotFoundException(String message) {
super(message);
}
}
インターフェース
JAVA
// 書籍管理インターフェース
public interface BookManager {
void addBook(Book book);
void removeBook(String isbn);
Book findBook(String isbn);
List<Book> getAllBooks();
}
// 読者管理インターフェース
public interface ReaderManager {
void addReader(Reader reader);
void removeReader(String id);
Reader findReader(String id);
List<Reader> getAllReaders();
}
管理クラス
JAVA
import java.util.*;
// Libraryクラス
public class Library implements BookManager, ReaderManager {
private Map<String, Book> books;
private Map<String, Reader> readers;
public Library() {
this.books = new HashMap<>();
this.readers = new HashMap<>();
}
// 書籍管理
@Override
public void addBook(Book book) {
books.put(book.getIsbn(), book);
System.out.println("書籍追加: " + book.getTitle());
}
@Override
public void removeBook(String isbn) {
Book book = books.remove(isbn);
if (book != null) {
System.out.println("書籍削除: " + book.getTitle());
} else {
System.out.println("書籍が見つかりません");
}
}
@Override
public Book findBook(String isbn) {
return books.get(isbn);
}
@Override
public List<Book> getAllBooks() {
return new ArrayList<>(books.values());
}
// 読者管理
@Override
public void addReader(Reader reader) {
readers.put(reader.getId(), reader);
System.out.println("読者追加: " + reader.getName());
}
@Override
public void removeReader(String id) {
Reader reader = readers.remove(id);
if (reader != null) {
System.out.println("読者削除: " + reader.getName());
} else {
System.out.println("読者が見つかりません");
}
}
@Override
public Reader findReader(String id) {
return readers.get(id);
}
@Override
public List<Reader> getAllReaders() {
return new ArrayList<>(readers.values());
}
// 書籍貸出
public void borrowBook(String isbn, String readerId)
throws BookAlreadyBorrowedException, ReaderNotFoundException {
Book book = books.get(isbn);
if (book == null) {
System.out.println("書籍が見つかりません");
return;
}
if (book.isBorrowed()) {
throw new BookAlreadyBorrowedException("書籍はすでに貸出中: " + book.getTitle());
}
Reader reader = readers.get(readerId);
if (reader == null) {
throw new ReaderNotFoundException("読者が見つかりません: " + readerId);
}
book.setBorrowed(true);
reader.borrowBook(book);
System.out.println(reader.getName() + "が" + book.getTitle() + "を借りました");
}
// 書籍返却
public void returnBook(String isbn, String readerId)
throws BookNotBorrowedException, ReaderNotFoundException {
Book book = books.get(isbn);
if (book == null) {
System.out.println("書籍が見つかりません");
return;
}
if (!book.isBorrowed()) {
throw new BookNotBorrowedException("書籍は貸出中ではありません: " + book.getTitle());
}
Reader reader = readers.get(readerId);
if (reader == null) {
throw new ReaderNotFoundException("読者が見つかりません: " + readerId);
}
book.setBorrowed(false);
reader.returnBook(book);
System.out.println(reader.getName() + "が" + book.getTitle() + "を返却しました");
}
}
メインプログラム
JAVA
import java.util.Scanner;
public class LibrarySystem {
private static Library library = new Library();
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
// データ初期化
initData();
// メインループ
int choice;
do {
showMenu();
choice = scanner.nextInt();
scanner.nextLine(); // 改行を消費
switch (choice) {
case 1: listBooks(); break;
case 2: listReaders(); break;
case 3: borrowBook(); break;
case 4: returnBook(); break;
case 5: addBook(); break;
case 6: addReader(); break;
case 0: System.out.println("さようなら!"); break;
default: System.out.println("無効な選択");
}
} while (choice != 0);
scanner.close();
}
private static void initData() {
library.addBook(new Book("978-7-111-40701-0", "Javaプログラミング", "Bruce Eckel"));
library.addBook(new Book("978-7-111-21382-6", "デザインパターン", "GoF"));
library.addBook(new Book("978-7-115-22170-8", "アルゴリズム入門", "CLRS"));
library.addReader(new Reader("R001", "Alice"));
library.addReader(new Reader("R002", "Bob"));
}
private static void showMenu() {
System.out.println("\n=== 図書管理システム ===");
System.out.println("1. 書籍一覧");
System.out.println("2. 読者一覧");
System.out.println("3. 書籍貸出");
System.out.println("4. 書籍返却");
System.out.println("5. 書籍追加");
System.out.println("6. 読者追加");
System.out.println("0. 終了");
System.out.print("選択してください: ");
}
private static void listBooks() {
System.out.println("\n--- 書籍一覧 ---");
for (Book book : library.getAllBooks()) {
System.out.println(book);
}
}
private static void listReaders() {
System.out.println("\n--- 読者一覧 ---");
for (Reader reader : library.getAllReaders()) {
System.out.println(reader);
}
}
private static void borrowBook() {
System.out.print("ISBNを入力: ");
String isbn = scanner.nextLine();
System.out.print("読者IDを入力: ");
String readerId = scanner.nextLine();
try {
library.borrowBook(isbn, readerId);
} catch (BookAlreadyBorrowedException | ReaderNotFoundException e) {
System.out.println("エラー: " + e.getMessage());
}
}
private static void returnBook() {
System.out.print("ISBNを入力: ");
String isbn = scanner.nextLine();
System.out.print("読者IDを入力: ");
String readerId = scanner.nextLine();
try {
library.returnBook(isbn, readerId);
} catch (BookNotBorrowedException | ReaderNotFoundException e) {
System.out.println("エラー: " + e.getMessage());
}
}
private static void addBook() {
System.out.print("ISBNを入力: ");
String isbn = scanner.nextLine();
System.out.print("タイトルを入力: ");
String title = scanner.nextLine();
System.out.print("著者を入力: ");
String author = scanner.nextLine();
library.addBook(new Book(isbn, title, author));
}
private static void addReader() {
System.out.print("読者IDを入力: ");
String id = scanner.nextLine();
System.out.print("名前を入力: ");
String name = scanner.nextLine();
library.addReader(new Reader(id, name));
}
}
出力例
TEXT
=== 図書管理システム ===
1. 書籍一覧
2. 読者一覧
3. 書籍貸出
4. 書籍返却
5. 書籍追加
6. 読者追加
0. 終了
選択してください: 1
--- 書籍一覧 ---
[978-7-111-40701-0] Javaプログラミング - Bruce Eckel (貸出可能)
[978-7-111-21382-6] デザインパターン - GoF (貸出可能)
[978-7-115-22170-8] アルゴリズム入門 - CLRS (貸出可能)
選択してください: 3
ISBNを入力: 978-7-111-40701-0
読者IDを入力: R001
AliceがJavaプログラミングを借りました
設計のポイント
| 面 | 説明 |
|---|---|
| カプセル化 | プライベート属性、getter/setterでアクセス |
| 継承 | インターフェース継承(BookManager、ReaderManager) |
| ポリモーフィズム | インターフェース参照が実装を指す |
| 例外処理 | ビジネスエラー用のカスタム例外 |
| コレクション | 書籍と読者にMap、貸出記録にList |
❓ よくある質問
Q システムを拡張するにはどうすればいいですか?
A 書籍カテゴリ、貸出履歴、延滞料金などを追加してください。
Q データを永続化するにはどうすればいいですか?
A ファイルIOまたはデータベースを使用してデータを保存してください。
Q マルチスレッディングをサポートするにはどうすればいいですか?
A 同期化(synchronized)または並行コレクション(ConcurrentHashMap)を使用してください。
📖 まとめ
- クラス設計はカプセル化、継承、ポリモーフィズムを考慮すべき
- 例外処理によりプログラムがより堅牢になる
- インターフェースは契約を定義し、実装は詳細を処理
- コレクションクラス(Map、List)はデータストレージに使用
📝 演習
- 機能拡張: 書籍カテゴリとカテゴリベースの検索を追加
- 貸出履歴: 貸出履歴を記録し、履歴の表示をサポート
- データ永続化: データをファイルに保存し、プログラム起動時に読み込み
次のレッスン
次のレッスンでは、Phase 4に移り、コレクションフレームワーク概要を学びます — Javaコレクションシステムを理解します。



