O — Open/Closed Principle: модуль должен быть открыт для расширения и закрыт для изменения. Иначе говоря, чтобы добавить поведение, не нужно править работающий и протестированный код. Любая правка может сломать старые случаи, а новый класс старых не трогает.
Нарушение: цепочка if/elif
Для каждого нового вида скидки приходится дописывать ветку в discount(). С ростом функции старые тесты оказываются под угрозой.
def discount(kind, price):
if kind == "regular":
return price
elif kind == "student":
return price * 0.9
elif kind == "vip":
return price * 0.8
raise ValueError(f"unknown kind: {kind}")
for kind in ("regular", "student", "vip"):
print(kind, discount(kind, 100))
try:
discount("black-friday", 100) # a new case: we must edit discount()
except ValueError as err:
print(err)regular 100
student 90.0
vip 80.0
unknown kind: black-fridayСпособ 1: полиморфизм
Общий базовый класс (контракт) и подкласс для каждого случая. checkout() знает только контракт. Новый BlackFriday добавляется, и ничего не правится. Это строится на наследовании и ABC.