У меня есть следующий код с парой вложенных условий if-else, которые я хотел бы реорганизовать. Чтобы не усложнять пример, я не определяю вспомогательные функции (например, disable_check
, check_last_alarm
, get_kpi_value
, …)
if disable_check(config, date):
threshold = get_threshold()
last_date = get_last_date()
if check_last_alarm(config, date, update_freq):
kpi_value = get_kpi_value(config, last_date)
if trigger_kpi_alarm(kpi_value):
return kpi_value
if extraordinary_alarm(config, date, threshold):
kpi_value = get_kpi_value(config, last_date)
if trigger_kpi_alarm(kpi_value):
return kpi_value
Моя идея заключалась в том, чтобы применить шаблон проектирования цепочки ответственности, например (черновик)
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any, Optional
from performance_tracker_dashboard.src.helper_functions import
class Handler(ABC):
@abstractmethod
def set_next(self, handler: Handler) -> Handler:
pass
@abstractmethod
def handle(self, request) -> Optional[str]:
pass
class AbstractCheck(Handler):
_next_handler: Handler = None
def set_next(self, handler: Handler) -> Handler:
self._next_handler = handler
return handler
@abstractmethod
def handle(self, request: Any) -> str:
if self._next_handler:
return self._next_handler.handle(request)
return None
class DisableCheck(AbstractCheck):
def handle(self, request: Any) -> str:
# TODO - how to integrate logic?
if request == "last_alarm":
return f"Last Alarm was not sufficient"
else:
return super().handle(request)
class LastAlarmCheck(AbstractCheck):
def handle(self) -> str:
pass
class KPIAlarmCheck(AbstractCheck):
def handle(self) -> str:
pass
class ExtraordinaryCheck(AbstractCheck):
def handle(self) -> str:
pass
def client_code(handler: Handler) -> None:
# TODO- how to define the request arg?
result = handler.handle(request)
if __name__ == "__main__":
disable_check = DisableCheck()
last_alarm = LastAlarmCheck()
kpi_alarm = KPIAlarmCheck()
extraordinary_alarm = ExtraordinaryCheck()
disable_check.set_next(last_alarm).set_next(kpi_alarm).set_next(extraordinary_alarm).set_next(kpi_alarm)
client_code(disable_check)
Вопросов:
- Возможен ли этот шаблон проектирования для данной ситуации? Если нет, у вас есть альтернативная идея?
- Как реализовать методы конкретных проверочных классов? Некоторые из них могут принимать входные данные из предыдущего конкретного класса проверки, и я не уверен, как это реализовать.
Черновик основан на этой веб-странице: https://refactoring.guru/design-patterns/chain-of-responsibility/python/example