---
# System prepended metadata

title: チケット料金モデリング
tags: [DDD, モデリング]

---

チケット料金モデリング
===
###### tags: `DDD`

パッケージ図
![](https://i.imgur.com/FR8wcb4.png)

ドメインモデル図
![](https://i.imgur.com/p6XQROi.png)

```java=
class ScreenPricePatternTest {
  @Test
  void calcBasePriceTest() {
    assertBasePrice(CinemaCityCitizen60, WeekdayNormal, 1000);
    assertBasePrice(Normal, WeekdayNormal, 1800);
    assertBasePrice(Senior70, WeekdayNormal, 1100);
    // 以下略
  }
  
  private void assertBasePrice(ScreenPricePattern screenPricePattern, ScreenTimeType screenTimeType, int basePriceValue) {
    assertThat(screenPricePattern.calcPrice(screenTimeType), is(BasePrice.of(basePriceValue)));
  }
}
```


```java=
package org.littlehands.ticket_modeling.pricing;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 料金区分を表すクラス
 */
@AllArgsConstructor
@Getter
public enum ScreenPricePattern {
  // @formatter:off
  CinemaCityCitizenNormal (1000, 1000, 1300, 1000, 1100),
  CinemaCityCitizen60     (1000, 1000, 1000, 1000, 1000),
  Normal                  (1800, 1300, 1800, 1300, 1100),
  Senior70                (1100, 1100, 1100, 1100, 1100),
  UnivStudent             (1500, 1300, 1500, 1300, 1100),
  JuniorStudent           (1000, 1000, 1000, 1000, 1000),
  Child                   (1000, 1000, 1000, 1000, 1000),
  Handicapped             (1000, 1000, 1000, 1000, 1000),
  HandicappedJunior       ( 900,  900,  900,  900,  900),
  MiCardMember            (1600, 1300, 1600, 1300, 1100),
  ParkingPark             (1400, 1100, 1400, 1100, 1100);
  // @formatter:on

  private int weekdayNormalPrice;
  private int weekdayLateShowPrice;
  private int holidayNormalPrice;
  private int holidayLateShowPrice;
  private int movieDayPrice;

  public BasePrice calcPrice(ScreenTimeType screenTimeType) {
    switch (screenTimeType) {
      case WeekdayNormal:
        return BasePrice.of(this.weekdayNormalPrice);
      case WeekdayLateShow:
        return BasePrice.of(this.weekdayLateShowPrice);
      case HolidayNormal:
        return BasePrice.of(this.holidayNormalPrice);
      case HolidayLateShow:
        return BasePrice.of(this.holidayLateShowPrice);
      case MovieDay:
        return BasePrice.of(this.movieDayPrice);
      default:
        throw new IllegalArgumentException();
    }
  }

}
```

```java=
/**
 * 上映時間区分を表すクラス
 */
public enum ScreenTimeType {
  WeekdayNormal, WeekdayLateShow, HolidayNormal, HolidayLateShow, MovieDay
}
```

```java=
/**
 * 基本料金を表すクラス
 */
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class BasePrice {
  private int value;

  public int intValue() {
    return value;
  }

  public static BasePrice of(int value) {
    return new BasePrice(value);
  }
}
```

チケット料金モデリング 
===
###### tags: `DDD` `モデリング`

ユースケース図
```
@startuml
left to right direction

actor チケット購入者
rectangle {
  チケット購入者 --> (支払い金額を確認する)
   (支払い金額を確認する) ..> (割引を選択する) : <<include>>
   (支払い金額を確認する) ..> (映画、上映日時、枚数を選択する) : <<include>>
}

note bottom of チケット購入者
前提
・当日会場で購入するときの処理とする
・映画→上映日時→枚数→割引の順番で選択するものとする
・支払い方法処理については一旦スコープアウトとする
end note
@enduml
```

ドメインモデル図
```
@startuml
skinparam packageStyle rectangle

package 映画 {
  object 映画 {
    映画ID
    タイトルなどその他諸々
  }
  object 映像Dimension{
    dimension(2D/3D)
  }
  映画 "1" *-u- "1" 映像Dimension
}



package 上映 {
  object 上映 {
    上映ID
    映画ID
  }

  object 上映時間 {
    曜日区分 (平日/土日祝)
    レイト時間帯 (true/false)
    映画の日 (true/false)
  }
  上映 "1" *-- "1" 上映時間
}
映画 <-u- 上映



package 予約 {
  object 予約 {
  上映ID
  }
  object 適用3Dオプション {
    3Dオプション区分(なし
    　　/メガネレンタル/メガネ持参)
  }
  予約 "1" *-- "1" 適用3Dオプション

  object 座席予約 {
    年齢区分 (一般/70歳以上/学生(大・専)
    　　　　　/中・高校生/幼児(3才以上)・小学生)
    障害者 (true/false)
  }
  予約 "1" *-- "1..n" 座席予約

  object 適用割引 {
    割引タイプ (シネマシティズン
    　　 /エムアイカード/駐車場パーク80割引)
  }
  座席予約 "1" *-- "0..1" 適用割引

  note top of 適用割引
  ・割引は1つしか適用されない
  ・シネマシティズンは年齢によって割引幅が変わる
  end note
  note top of 座席予約
  ・1座席予約で1名分を表す
  ・障害者割引は同伴者１名にも適用されるので、
  　計算時に考慮する。
  ・シニア、学生、中高生は身分証提示必要
  　オペレーションで確認するのでシステム上追加対応なし
  end note
}
予約 --> 上映


package 料金設定 {
  object 上映時間区分 {
    曜日区分 (平日/土日祝)
    レイト時間帯 (true/false)
    映画の日 (true/false)
  }
  object 上映時間区分Calculator {
  }
  上映時間区分 <-d- 上映時間区分Calculator
  上映時間区分Calculator -u-> 上映時間


  object 料金区分 {
    料金区分(一般/シニア/シネマシティズン 等)
  }
  object 料金区分Calculator
  料金区分 <-d- 料金区分Calculator
  上映時間区分 <-r- 料金区分
  note left of 料金区分Calculator
  ・入力した年齢、割引などをもとに
  　どの区分か判断する
  end note
  note left of 料金区分
  ・料金区分×時間区分の
  　基本料金はここに定義する
  end note

  object 3Dオプション {
    3Dオプション区分
    値段
  }
  適用3Dオプション --> 3Dオプション
}
座席予約               <-u- 料金区分Calculator
適用割引               <-u- 料金区分Calculator



package 支払い料金 {
  object 支払い料金 {
    合計金額
  }
}
上映時間区分             <-- 支払い料金
3Dオプション          <-- 支払い料金
料金区分              <-- 支払い料金
note bottom of 支払い料金
・1〜N件の座席予約を元に計算する
end note



note as N1
・単一映画館が前提とする
・特別興行の場合は考慮しない
end note

@enduml
```

パッケージ図
```
@startuml
skinparam packageStyle rectangle


object 映画
object 上映
object 予約
object 料金設定
object 支払い料金

映画 <-- 上映
上映 <-l- 予約
上映 <-- 料金設定
予約 <-- 料金設定
料金設定 <-l- 支払い料金

@enduml
```

