サブスクを管理するクラスを作ることになった
class Subscription:
def __init__(self, plan_id: int, price: int):
self.__plan_id = plan_id
self.__monthly_price = price
def plan_id(self):
return self.__plan_id
def monthly_price(self):
return self.__monthly_price
割引機能の追加が要望される
- 20%オフとかそういうのときの割引後の金額で計算できるようにしといてよ。
- あと具体的にお得になった割引額も計算できるといいな
class Subscription:
# ...
def monthly_price(self):
"割引後の価格を計算する"
return int(self.__monthly_price * (1 - self.__discount_rate))
def rate_discount(self, discount_rate: float):
"割引率を設定する"
self.__discount_rate = discount_rate
def compute_discounted_amount(self):
"割引される額を計算する"
return self.__monthly_price - self.monthly_price()
sub = Subscription(plan_id=12345, price=1000) # 1000円のプランを購読
sub.rate_discount(0.2) # 20% OFF
print(sub.monthly_price()) # => 800円
固定値の値引き機能の追加も要望される
class Subscription:
# ...
def monthly_price(self):
"割引後の価格を計算する"
# 割引方法が二種類あるので条件分岐
match self.__discount_type:
case "rate":
# 割引なので self.__discount_rate を元に計算
return int(self.__monthly_price * (1 - self.__discount_rate))
case "value":
# 固定値値引きなので self.__discount_value を元に計算
return self.__monthly_price - self.__discount_value
case _:
raise RuntimeError()
def rate_discount(self, discount_rate: float):
"割引率を設定する"
self.__discount_type = "rate"
self.__discount_rate = discount_rate
def value_discount(self, discount_value: int):
"割引額を設定する"
self.__discount_type = "value"
self.__discount_value = discount_value
# ...
sub = Subscription(plan_id=12345, price=1000) # 1000円のプランを購読
sub.rate_discount(0.2) # 20% OFF
print(sub.monthly_price()) # => 800円
sub = Subscription(plan_id=12345, price=1000) # 1000円のプランを購読
sub.value_discount(300) # 300円 OFF
print(sub.monthly_price()) # => 700円
依頼はもっと複雑に…
その日の晩、Aさんはこんな夢を見ました。
- 割引と固定値値引きを順番に適用するとか、
- 初月無料のキャンペーンとか、
- セット割で一定期間だけ値引き値や割合の増額とか、
そういうの実装してくれないかな。
なにがよくなかったのか
こいつがじわじわ効いてきています。
def monthly_price(self):
"割引後の価格を計算する"
# 割引方法が二種類あるので条件分岐
match self.__discount_type:
case "rate":
return int(self.__monthly_price * (1 - self.__discount_rate))
case "value":
return self.__monthly_price - self.__discount_value
case _:
raise RuntimeError()
-
サブスクを管理するクラスの中にキャンペーンのロジックまで混ぜ込もうとしてしまったこと。
実は、これは後で説明するSOLID原則の「S: 単一責任の原則」に対する違反です。
-
いろいろな種類のキャンペーンを一つのクラス内の条件分岐で頑張ろうとしたこと。
実は、これは後で説明するSOLID原則の「S: 単一責任の原則」に加え、「O: オープン・クローズドの原則」に対する違反でもあります。
どうすればよかったのか
→ クラスを分ける。
-
サブスクそのものを管理するクラス
Subscription
-
割引等のキャンペーンを管理するクラス
RateDiscountCampaign
/ValueDiscountCampaign
次: 📄 【オブジェクト指向2024 #5】処理の見通しを良くするには