はじめに
以下の本を勉強しています。
良いコード/悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方
とても勉強になるのですが、次の点で不便を感じました。
課題
- 自分にJavaの知見がなく、本に記載されているコードの意図が分かりにくい
- 本には触れられるサンプルコードが用意されていない
(不明点をChatGPTで確認したいが、サンプルコードがないので確認しづらい) - 全部コードを手打ちするのはしんどい
※すみません、サンプルコードあるみたいです(旧版バージョン)
https://gihyo.jp/book/2022/978-4-297-12783-1/support
解決方法
本には クラス図 が載っているので、それを ChatGPT に渡してコード化してもらう、という方法を取りました。
例: 図7.1のコード
// ChatGPTへのプロンプト
Partyクラス
Party()
Party(members: List<Member>)
add(newMember: Member) : Party
isAlive(): boolean
exists(member: Member): boolean
isFull(): boolean
Memberクラス
id: int
isAlive(): boolean
上記を元にJavaのサンプルコードを作って
生成されたコード
※ 本の内容と完全に同じではありません
src/list7_14/Party.java
package src.list7_14;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// Party クラス
public class Party {
private static final int MAX_SIZE = 4; // 定員
private final List<Member> members;
// 空の Party
public Party() {
// new ArrayList<>() は 空のリストを作る処理
this.members = new ArrayList<>();
}
// 既存のメンバーを持つ Party(private に変更)
private Party(List<Member> members) {
this.members = new ArrayList<>(members);
}
// 新しいメンバーを追加した Party を返す(不変オブジェクト風)
// ポイント:
// 1. 元の Party の members は変更しない
// 2. this.members は final で、直接追加や削除はされない
// 3. 新しい Party オブジェクトを返す
// 4. メンバー追加の結果は新しいオブジェクトで表現される
// 5. 元の Party はそのまま
public Party add(Member newMember) {
if (isFull()) {
throw new IllegalStateException("Party is full");
}
List<Member> newMembers = new ArrayList<>(members);
newMembers.add(newMember);
return new Party(newMembers);
}
// 少なくとも 1 人が生存しているか
public boolean isAlive() {
return members.stream().anyMatch(Member::isAlive);
}
// 指定メンバーがいるか
public boolean exists(Member member) {
return members.contains(member);
}
// 定員に達しているか
public boolean isFull() {
return members.size() >= MAX_SIZE;
}
// メンバー一覧を返す(外部から変更できないようにする)
public List<Member> getMembers() {
return Collections.unmodifiableList(members);
}
}
src/list7_14/Member.java
package src.list7_14;
import java.util.Objects;
// Member クラス
public class Member {
private final int id;
private final boolean alive;
public Member(int id, boolean alive) {
this.id = id;
this.alive = alive;
}
public int getId() {
return id;
}
public boolean isAlive() {
return alive;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Member))
return false;
Member member = (Member) o;
return id == member.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
src/list7_14/Main.java
package src.list7_14;
public class Main {
public static void main(String[] args) {
Member taro = new Member(1, true);
Member hanako = new Member(2, true);
Party party1 = new Party();
Party party2 = party1.add(taro);
Party party3 = party2.add(hanako);
System.out.println("party1 size: " + party1.getMembers().size());
System.out.println("party2 size: " + party2.getMembers().size());
System.out.println("party3 size: " + party3.getMembers().size());
}
}
補足
サンプルコードをリスト番号で整理したかったのですが、Javaでは ファイル名に番号を入れるより、ディレクトリ名に番号を付ける方がわかりやすかったです。
(ファイル名とクラス名を揃える必要があるため、ファイル名に番号を入れるとクラス名に番号が入ってしまう)
src > リスト番号(list7_14など) > 各ファイル
終わりに
ChatGPTを使うことで、Javaの細かい文法に悩まずにコードを準備でき、
本の内容である「良い設計とは何か」という本質的な部分に集中して学習できるようになりました。
Java初心者の方がこの本を読む際にも、同じように クラス図 → コード化 → 実行 の流れを作ると理解が深まりやすいと思います。