# 業務ロジック — Vet.getSpecialties() [6 LOC]

| 項目 | 値 |
|-------|-------|
| 完全修飾名 | `org.springframework.samples.petclinic.vet.Vet` |
| レイヤー | Entity (ドメインモデル) |
| モジュール | `vet` (パッケージ: `org.springframework.samples.petclinic.vet`) |

## 1. 役割

### Vet.getSpecialties()

本メソッドは、動物病院（Pet Clinic）システムにおける獣医師（`Vet`）の専門分野（`Specialty`）一覧を、名前の昇順に整列させたリストとして返す getter メソッドである。獣医師は複数の専門分野を持つことができ、例えば「外科（Surgery）」や「内科（Internal Medicine）」などの分類で管理される。

本メソッドは JAX-B アノテーション（`@XmlElement`）が付与されており、XML シリアライゼーション時に XML 要素として公開されることを意図している。内部状態である `specialties` セットを直接公開するのではなく、`getSpecialtiesInternal()` を介して取得したセットをストリーム処理により昇順に整列させた後、新規の `List` として返すことで、外部からの破壊的な変更（要素の追加・削除・ソート変更）から内部状態を保護する防御的なコピー（defensive copy）の設計パターンを採用している。

本メソッドはエンティティ自体のアクセサとして振る舞い、ビュー層や REST API 層から獣医師の情報とともに専門分野の一覧を取得する際の共通のエントリポイントとなる。システム全体では、獣医師の検索画面や検索結果リストにおいて、各獣医師の専門分野をクライアントへ送信する際に使用される。

## 2. 処理パターン（詳細業務ロジック）

```mermaid
flowchart TD
    START(["getSpecialties()"])
    CALL_INTERNAL["getSpecialtiesInternal()"]
    STREAM["stream()"]
    SORTED["sorted(Comparator.comparing(NamedEntity::getName))"]
    COLLECT["collect(Collectors.toList())"]
    RETURN(["Return List<Specialty>"])

    START --> CALL_INTERNAL
    CALL_INTERNAL --> STREAM
    STREAM --> SORTED
    SORTED --> COLLECT
    COLLECT --> RETURN
```

本メソッドの処理は、直列なストリーム処理チェーンにより構成される。

1. `getSpecialtiesInternal()` を呼び出し、獣医師の専門分野セットを取得する。この際、セットが null であれば空の `HashSet` で初期化する。
2. 取得したセットに対してストリームを作成し、`NamedEntity` の `name` プロパティで昇順に整列する。
3. 整列済みのストリームを `List` に収集して返す。

条件分岐は本メソッド内には存在せず、すべての処理は内部メソッド `getSpecialtiesInternal()` に委譲されている。

## 3. パラメータ分析

| No | パラメータ名 | 型 | 業務的説明 |
|----|---------------|------|---------------------|
| - | (該当なし) | - | 本メソッドは引数を取らない。 |

### 参照するインスタンスフィールド・外部状態

| フィールド名 | 型 | 業務的説明 |
|---------------|------|---------------------|
| `specialties` | `Set<Specialty>` | 獣医師が持つ専門分野の集合。`@ManyToMany` 関連によりデータベースの `vet_specialties` 結合テーブルからフェッチされる。 null チェック後に遅延初期化される。 |

## 4. CRUD操作／呼び出しサービス

### コード解析グラフからの事前抽出エビデンス:

| CRUD | SC / CBS | SCコード | エンティティ / DB | 操作の説明 |
|------|----------|---------|-------------|----------------------|
| R | `Vet.getSpecialtiesInternal` | - | - | `Vet` クラス内の `getSpecialtiesInternal` を呼び出す |

| CRUD | SC / CBS | SCコード | エンティティ / DB | 操作の説明 |
|------|----------|---------|-------------|----------------------|
| R | `Vet.getSpecialtiesInternal` | - | `vets`, `vet_specialties`, `specialties` | 獣医師の専門分野セットを null チェック付きで取得。JPA の `@ManyToMany` フェッチにより `vet_specialties` 結合テーブルを通じて関連する専門分野レコードを読み出す。 |
| R | `NamedEntity.getName` | - | `Specialty.name` | ストリームのソート処理において、各専門分野エンティティの `name` プロパティ（専門分野名）を読み出す。 |

**操作分類の理由:**

- **R (Read)**: `getSpecialtiesInternal()` は内部フィールド `specialties` の参照を返すだけであり、新しいデータを作成・更新・削除しない。`NamedEntity::getName` も同様に既存プロパティの読み出しのみを実行する。

## 5. 依存関係トレース

### コード解析グラフからの事前抽出エビデンス:

画面/バッチのエントリポイントは見つかりませんでした（探索範囲 8 ホップ）。直接の呼び出し元: 1 件のメソッド。
本メソッドからの終端操作: `getSpecialtiesInternal` [R]

| # | 呼び出し元（画面/バッチ） | 呼び出しチェーン（本メソッドまでの全経路） | 終端（SC / CRUD / エンティティ） |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | `ClinicServiceTests.shouldFindVets()` | `ClinicServiceTests.shouldFindVets()` -> `Vet.getSpecialties` | `getSpecialtiesInternal [R] vets, vet_specialties, specialties` |

**呼び出し元の説明:**

- `ClinicServiceTests.shouldFindVets()` は、獣医師検索機能のユニットテストであり、 `ClinicService` から取得した獣医師一覧に対して、各獣医師が専門分野を持っていることを検証するために `getSpecialties()` を呼び出している。

## 6. 分岐ごとの詳細ブロック

本メソッドには条件分岐（if/else, switch/case）が含まれていないため、単一の直列ブロックとして記述する。

**ブロック 1** — [EXEC] `(ストリーム処理チェーン)` (L59-L64)

本ブロックでは、内部メソッド経由で取得した専門分野セットをストリーム処理により昇順ソートしたリストとして返却している。

| # | 種別 | コード |
|---|------|------|
| 1 | CALL | `getSpecialtiesInternal()` |
| 2 | EXEC | `stream()` — セットからストリームを作成 |
| 3 | EXEC | `sorted(Comparator.comparing(NamedEntity::getName))` — 専門分野名で昇順ソート |
| 4 | EXEC | `collect(Collectors.toList())` — ソート済みのストリームを `List` に収集 |
| 5 | RETURN | `return ... ;` — 整列済みの `List<Specialty>` を返す |

### 内部メソッド `getSpecialtiesInternal()` に関する補足

`getSpecialtiesInternal()` には null チェックによる分岐が存在する。

**ブロック 1.1** — [IF] `(this.specialties == null)` (L56)

`specialties` フィールドが null である場合、空の `HashSet` で初期化を行う。

| # | 種別 | コード |
|---|------|------|
| 1 | SET | `this.specialties = new HashSet<>();` — 空のセットで遅延初期化 |
| 2 | RETURN | `return this.specialties;` — セット参照を返す |

**ブロック 1.2** — [ELSE-IF] `(this.specialties != null)` — 暗黙の else 分岐 (L59)

`specialties` が null でない場合、既存のセット参照をそのまま返す。

| # | 種別 | コード |
|---|------|------|
| 1 | RETURN | `return this.specialties;` — 既存セットをそのまま返す |

## 7. 用語集

| 用語 | 種別 | 業務的意味 |
|------|------|------------------|
| `Vet` | Entity | 獣医師 — 動物病院で患者（ペット）を診察・治療する専門職を表現する JPA エンティティ |
| `Specialty` | Entity | 専門分野 — 獣医師が持つ特定の診療分野（例：外科、内科）を表現する JPA エンティティ |
| `specialties` | Field | 専門分野リスト — 獣医師が保有する専門分野の集合。`@ManyToMany` 関連により多対多の関係で `vet_specialties` 結合テーブルにマッピングされる |
| `vet_specialties` | Table | 獣医師-専門分野結合テーブル — `Vet` と `Specialty` の多対多関連を解消する中間テーブル。`vet_id` と `specialty_id` のカラムを持つ |
| `specialties` | Table | 専門分野マスタテーブル — 利用可能な専門分野の種類（外科、内科など）を定義するテーブル。`id` と `name` のカラムを持つ |
| `NamedEntity` | Entity | 名前付きエンティティ基底クラス — `name` プロパティを共通で持つエンティティの抽象基底クラス。`Specialty` がこれを継承する |
| `getSpecialtiesInternal` | Method | 内部アクセサ — null チェック付きで `specialties` セットを取得する protected メソッド。外部に直接公開されず、防御的なコピーを返す `getSpecialties()` から呼び出される |
| `@XmlElement` | Annotation | JAX-B アノテーション — XML シリアライゼーション時にこのメソッドの戻り値を XML 要素として出力することを指示する |
| `@ManyToMany` | Annotation | JPA 注釈 — 多対多のエンティティ関連を定義する。`fetch = FetchType.EAGER` により即時フェッチを行う |
| `@JoinTable` | Annotation | JPA 注釈 — 結合テーブルの名前と結合カラムを定義する |
| `ClinicServiceTests` | TestClass | 診療所サービステスト — `ClinicService` のユニットテストクラス。獣医師検索機能の動作を検証する |
| `List<Specialty>` | Type | 専門分野リスト — 整列済みの専門分野エンティティのリスト。メソッドの戻り値型。外部からの内部セット変更を防ぐために新しいリストインスタンスとして返される |
