✍️
【ドメイン駆動設計】値オブジェクト「価格」の設計例
🎯目的
ドメイン駆動設計の具体例を記載し、ドメイン駆動設計を実践できるようにする
💡前提
この記事では、実践ドメイン駆動設計 | ヴォーン・ヴァーノン, 髙木 正弘 |本 | 通販 | Amazonを参考にしています。
💡「価格」とは
ここではECサイトで販売している商品の「価格」を取り上げます。尚、ここでの設計はあくまで例です。通常は扱うドメイン領域やユビキタス言語によって、設計が変わります。
商品の価格には、次の種類があります。
- 通常価格
- 割引価格
- 期間限定での割引
- 「5,000円以上のお買い上げで〜」などの条件付き割引 - 会員価格
- ECサイトで会員になっている人限定の価格
- 会員のランク(プレミアム、スタンダード、...)などによって価格が変わることもある
通常価格
割引価格
会員価格
✍️「価格」の設計
✍️自己参照方式の実装パターン
価格
from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
from typing import Optional
@dataclass(init=False, unsafe_hash=True, frozen=False)
class Price:
amount: float
currency: Currency
type: PriceType
other_price: Optional[Price]
class PriceType(Enum):
NORMAL_PRICE = "通常価格"
DISCOUNT_PRICE = "割引価格"
MEMBER_PRICE = "会員価格"
class Currency(Enum):
JPY = "日本円"
USD = "米ドル"
def __init__(self, amount: float, currency: Price.Currency, type: PriceType = PriceType.NORMAL_PRICE):
assert (isinstance(amount, float) or isinstance(amount, int)) and amount >= 0, \
"amountには0以上のfloat/int型を指定してください。"
assert isinstance(currency, Price.Currency), "currencyにはPrice.Currency型を指定してください。"
assert isinstance(type, Price.PriceType), "typeにはPrice.PriceType型を指定してください。"
super().__setattr__("amount", amount)
super().__setattr__("currency", currency)
super().__setattr__("type", type)
super().__setattr__("other_price", None)
def set_other_price(self, price: Price) -> Price:
self.other_price = price
return self.other_price
def type_of(self, price_type: PriceType) -> Optional[Price]:
if self.type == price_type:
return self
if self.other_price is not None:
return self.other_price.type_of(price_type)
return None
✍️インターフェース方式の実装パターン
書き途中
価格(インターフェース)
class Price(abc.ABC):
@abc.abstractmethod
def type(self) -> PriceType:
pass
@abc.abstractmethod
def match(self, consumer) -> bool:
pass
Discussion