# 業務ロジック — Owner.addVisit() [11 LOC]

| 項目 | 値 |
|-------|-------|
| 完全修飾名 | `org.springframework.samples.petclinic.owner.Owner` |
| レイヤー | Service |
| モジュール | `owner` (パッケージ: `org.springframework.samples.petclinic.owner`) |

## 1. 役割

### Owner.addVisit()

本メソッド `Owner.addVisit()` は、ペットクリニックの来院記録（Visit）を特定のペットに紐づけて登録するビジネスオペレーションである。 veterinary（獣医）業務における「来院」の概念をドメインモデル上に追加する役割を担う。具体的には、パラメータとして受け取った `petId` で識別される `Pet` エンティティを検索し、そこに `Visit` オブジェクトを関連付けする。

本メソッドは、パラメータのnullチェックとエンティティの存在チェックという二重のガード節パターンを実装しており、不正な状態が内部のコレクションに侵入するのを防いでいる。設計パターンとしては、委譲（Delegation）パターンを採用しており、実際のコレクションへの追加処理は `Pet.addVisit()` に委譲している。

本メソッドはシステム全体のエントリーポイントとして機能し、`VisitController` などのコントローラ層から呼び出されることで、HTTPリクエスト経由での来院情報登録を可能にする。Ownerが複数のPetを保持するというドメインモデルにおいて、特定のPetにのみ来院記録を追加するためのルータとしても振る舞う。

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

```mermaid
flowchart TD
    START(["addVisit(Integer petId, Visit visit)"])

    START --> COND1{petId is null?}
    COND1 -- Yes --> THROW1["Assert.notNull throw: Pet identifier must not be null!"]
    COND1 -- No --> CHECK2{visit is null?}
    CHECK2 -- Yes --> THROW2["Assert.notNull throw: Visit must not be null!"]
    CHECK2 -- No --> FETCH["Pet pet = getPet(petId)"]
    FETCH --> COND3{pet is null?}
    COND3 -- Yes --> THROW3["Assert.notNull throw: Invalid Pet identifier!"]
    COND3 -- No --> DELEGATE["pet.addVisit(visit)"]
    DELEGATE --> END_NODE(["Return void"])
    THROW1 --> END_NODE
    THROW2 --> END_NODE
    THROW3 --> END_NODE
```

**処理概要:**
本メソッドは、パラメータ検証 → ペット取得 → 存在検証 → 委譲追加の4ステップで構成されるガード節パターンである。各ステップで条件に違反すると `IllegalArgumentException` がスローされ、処理が早期終了する。正常系のみが `pet.addVisit(visit)` への委譲に進む。

## 3. パラメータ分析

| No | パラメータ名 | 型 | 業務的説明 |
|----|---------------|------|---------------------|
| 1 | `petId` | `Integer` | 来院記録を追加対象とするペットを特定する内部識別子。Ownerが保持する複数のPetのうち、どのPetに来院情報を紐づけるかを決定する。nullであることは許されず、nullの場合には `IllegalArgumentException` がスローされる。 |
| 2 | `visit` | `Visit` | 登録する来院記録そのものを表すドメインオブジェクト。来院日、獣医師の所見、メモなどの臨床情報を含む。nullであることは許されず、nullの場合には `IllegalArgumentException` がスローされる。 |

| # | 内部状態 | 型 | 業務的説明 |
|---|----------|------|---------------------|
| 1 | `this.pets` | `Collection<Pet>` | 本Ownerに紐づくペットのコレクション。`getPet(petId)` の検索対象となる。 |

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

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

| CRUD | SC / CBS | SCコード | エンティティ / DB | 操作の説明 |
|------|----------|---------|-------------|----------------------|
| R | `Owner.getPet` | - | `Pet` (JPA Entity) | `petId` でOwnerが保持するPetを検索する。コレクションを走査し、IDが一致するPetを返す。存在しない場合は `null` を返す。 |
| C | `Pet.addVisit` | - | `Visit` (JPA Entity) | 対象Petの内部コレクション（LinkedHashSet）に来院記録を追加する。JPACascadeによって `Visit` の永続化も同時に実行される。 |

**CRUD分類の根拠:**
- **R (Owner.getPet):** `getPet(Integer id)` はコレクションの走査による読み取り専用操作であり、エンティティの更新は行わない。内部では `getPets()` でコレクションを取得し、`pet.isNew()` と `pet.getId()` で一致判定する。
- **C (Pet.addVisit):** `addVisit(Visit visit)` はPetエンティティが保持する `visits` コレクション（`LinkedHashSet<Visit>`）への追加操作である。`CascadeType.ALL` および `FetchType.EAGER` の設定により、追加された `Visit` は自動的にデータベースに永続化される。

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

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

| # | 呼び出し元（画面/バッチ） | 呼び出しチェーン（メソッドまでの全経路） | 終端（SC / CRUD / エンティティ） |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | Controller:VisitController | `VisitController.processNewVisitForm` -> `Owner.addVisit` | `addVisit` [C], `getPet` [R], `getPet` [R], `getPet` [R] |
| 2 | Tester:ClinicServiceTests | `ClinicServiceTests.shouldAddNewVisitForPet` -> `Owner.addVisit` | `addVisit` [C], `getPet` [R], `getPet` [R], `getPet` [R] |

**呼び出し元の詳細:**
- **#1 `VisitController.processNewVisitForm`:** 来院情報入力画面からのPOSTリクエストを処理するコントローラメソッド。新規来院フォームの送信後に本メソッドを呼び出し、ペットへの来院登録を完了させる。Web層のエントリポイント。
- **#2 `ClinicServiceTests.shouldAddNewVisitForPet`:** `ClinicService` のユニットテスト。新規来院の追加が正しく動作することを検証するためのテストケース。本メソッドのテスト実装上の呼び出し元。

**本メソッドが呼び出す終端処理:**
- `getPet(petId)` [R] — Owner内部のPetコレクションからIDで検索（コレクション走査、3件分呼び出し）
- `pet.addVisit(visit)` [C] — Petエンティティの内部コレクションにVisitを追加（JPACascade経由でDBに永続化）

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

本メソッドはガード節パターンに基づく4つのブロックで構成される。各ブロックはパラメータ検証およびエンティティ検索の結果に応じて、正常パスまたは例外スローに分岐する。

**ブロック 1** — IF `[petId is null]` (L167)

> `petId` パラメータのnullチェック。nullの場合、直ちに例外をスローして処理を終了する。

| # | 種別 | コード |
|---|------|------|
| 1 | EXEC | `Assert.notNull(petId, "Pet identifier must not be null!");` // Spring FrameworkのAssert utilitiesによるnullチェック。nullの場合は IllegalArgumentException をスロー |

**ブロック 2** — IF `[visit is null]` (L168)

> `visit` パラメータのnullチェック。petIdのnullチェックが通過した場合のみ実行される。

| # | 種別 | コード |
|---|------|------|
| 1 | EXEC | `Assert.notNull(visit, "Visit must not be null!");` // 来院記録オブジェクトのnullチェック。nullの場合は IllegalArgumentException をスロー |

**ブロック 3** — EXEC `[getPet(petId) の呼び出し]` (L170)

> パラメータ検証が通過した後に実行。Ownerが保持するPetコレクションから `petId` で識別されるPetを検索する。

| # | 種別 | コード |
|---|------|------|
| 1 | SET | `Pet pet = getPet(petId);` // Owner.getPets() でコレクションを取得し、各PetのIDと一致判定。一致するPetがない場合は null |

**ブロック 4** — IF `[pet is null]` (L172)

> `getPet(petId)` の戻り値に対する存在チェック。指定されたIDのPetが存在しない場合は例外スロー。

| # | 種別 | コード |
|---|------|------|
| 1 | EXEC | `Assert.notNull(pet, "Invalid Pet identifier!");` // 該当Petが存在しないことを示す。IllegalArgumentException をスロー |

**ブロック 5** — EXEC `[pet.addVisit(visit) の委譲]` (L174)

> 全検証が通過した正常パス。PetエンティティにVisitの追加を委譲する。

| # | 種別 | コード |
|---|------|------|
| 1 | CALL | `pet.addVisit(visit);` // Petエンティティの内部コレクションへVisitを追加。JPACascade.ALLによりVisitも同時に永続化 |

## 7. 用語集

| 用語 | 種別 | 業務的意味 |
|------|------|---------------------|
| `visit` | Parameter | 来院記録 — ペットがクリニックを訪れた際の診療情報を記録するドメインオブジェクト。来院日、所見、メモ等の臨床情報を含む。 |
| `petId` | Parameter | ペット識別子 — Ownerが飼育する個々のペットを一意に特定するための内部ID。データベースの主キーに相当。 |
| `Owner` | Entity | 飼育者 — クリニックの顧客であるペットの所有者。1人のOwnerが複数のPetを所有する1対多の関係。 |
| `Pet` | Entity | ペット — クリニックで診療を受ける動物个体。名前、種類、生年月日、所有者等の属性を持つ。Visitコレクションを保持。 |
| `Visit` | Entity | 来院記録 — ペットの診療Visitごとに生成されるドメインオブジェクト。来院日付、獣医師の所見、任意のメモ等を記録。 |
| `Assert.notNull` | Utility | nullチェックユーティリティ — Spring Frameworkの検証ユーティリティクラス。第一引数がnullの場合は `IllegalArgumentException` をスローする。 |
| `LinkedHashSet` | Type | 順序付き集合 — Petエンティティが `visits` コレクションの型として使用するJavaコレクション。追加順序が保持され、重複要素を排除。 |
| `CascadeType.ALL` | JPA | キャスケード指定 — 親エンティティ（Pet）の変更操作（永続化、更新、削除等）を子エンティティ（Visit）にも同時に適用するJPAのアノテーション設定。 |
| `VisitController` | Controller | 来院コントローラ — HTTP経由での来院情報登録を処理するSpring MVCコントローラ。`processNewVisitForm` メソッドで本メソッドを呼び出す。 |
