ZEN_OF_PYTHON Telegram 4497
Цепочка обязанностей

Цепочка обязанностей (Chain of Responsibility, CoR) — поведенческий паттерн, который пропускает запрос через последовательность обработчиков, пока один из них не возьмётся за дело (или пока цепочка не закончится). Этот подход «развязывает» отправителя и получателей запроса: отправителю не нужно знать, кто именно обработает задачу, а обработчики остаются взаимозаменяемыми и настраиваемыми в рантайме.

Используйте CoR, если:

🔘 обработка запроса может зависеть от набора условий/правил, которые меняются со временем;
🔘 нужно включать / выключать шаги обработки без переписывания вызвавшего кода;
🔘 часть запросов может обрабатываться на ранних шагах, а остальные — «прокатываться» дальше;
🔘 вы строите конвейер: фильтры, middleware, валидаторы, пост-обработчики.


Минимальный состав паттерна

🔘 Handler (интерфейс / абстракция): объявляет метод handle(request) и хранит ссылку на «следующего»;
🔘 ConcreteHandler: решает, обрабатывать ли запрос, либо передаёт дальше;
🔘 Client: строит цепочку и отправляет запрос первому звену.


Пример


from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Optional, Any, Callable


class Handler(ABC):
def __init__(self, nxt: Optional["Handler"] = None):
self._next = nxt

def set_next(self, nxt: "Handler") -> "Handler":
self._next = nxt
return nxt # позволяет строить цепочку «в линию»

def handle(self, request: Any) -> Any:
# Базовая реализация: попытаться обработать здесь,
# иначе передать дальше.
result = self._handle_here(request)
if result is not None:
return result
if self._next:
return self._next.handle(request)
return None # никто не справился

@abstractmethod
def _handle_here(self, request: Any) -> Optional[Any]:
...


@dataclass
class HttpRequest:
path: str
headers: dict
user_id: Optional[int] = None
payload: Optional[dict] = None


class AuthHandler(Handler):
def _handle_here(self, req: HttpRequest) -> Optional[Any]:
token = req.headers.get("Authorization")
if not token:
# Нет токена — «решение на месте»: отклоняем и НЕ передаём дальше
return {"status": 401, "message": "Unauthorized"}
# валидируем (упростим) и ставим идентификатор
req.user_id = 42
return None # пропускаем дальше


class RateLimitHandler(Handler):
def __init__(self, check: Callable[[HttpRequest], bool], nxt: Optional[Handler] = None):
super().__init__(nxt)
self.check = check

def _handle_here(self, req: HttpRequest) -> Optional[Any]:
if not self.check(req):
return {"status": 429, "message": "Too Many Requests"}
return None


class RouterHandler(Handler):
def _handle_here(self, req: HttpRequest) -> Optional[Any]:
if req.path == "/me" and req.user_id:
return {"status": 200, "data": {"id": req.user_id}}
if req.path == "/ping":
return {"status": 200, "data": "pong"}
# Не мой маршрут — пропускаю дальше (если есть)
return None


class NotFoundHandler(Handler):
def _handle_here(self, req: HttpRequest) -> Optional[Any]:
# Терминальный обработчик: если дошли сюда — 404
return {"status": 404, "message": f"Route {req.path} not found"}


# Сборка цепочки
def build_pipeline() -> Handler:
auth = AuthHandler()
rate = RateLimitHandler(check=lambda r: True)
router = RouterHandler()
notfound = NotFoundHandler()

auth.set_next(rate).set_next(router).set_next(notfound)
return auth


if __name__ == "__main__":
pipeline = build_pipeline()
print(pipeline.handle(HttpRequest(path="/ping", headers={"Authorization": "Bearer x"})))
print(pipeline.handle(HttpRequest(path="/me", headers={"Authorization": "ok"})))
print(pipeline.handle(HttpRequest(path="/unknown", headers={"Authorization": "ok"})))
print(pipeline.handle(HttpRequest(path="/ping", headers={})))
Please open Telegram to view this post
VIEW IN TELEGRAM
6



tgoop.com/zen_of_python/4497
Create:
Last Update:

Цепочка обязанностей

Цепочка обязанностей (Chain of Responsibility, CoR) — поведенческий паттерн, который пропускает запрос через последовательность обработчиков, пока один из них не возьмётся за дело (или пока цепочка не закончится). Этот подход «развязывает» отправителя и получателей запроса: отправителю не нужно знать, кто именно обработает задачу, а обработчики остаются взаимозаменяемыми и настраиваемыми в рантайме.

Используйте CoR, если:

🔘 обработка запроса может зависеть от набора условий/правил, которые меняются со временем;
🔘 нужно включать / выключать шаги обработки без переписывания вызвавшего кода;
🔘 часть запросов может обрабатываться на ранних шагах, а остальные — «прокатываться» дальше;
🔘 вы строите конвейер: фильтры, middleware, валидаторы, пост-обработчики.


Минимальный состав паттерна

🔘 Handler (интерфейс / абстракция): объявляет метод handle(request) и хранит ссылку на «следующего»;
🔘 ConcreteHandler: решает, обрабатывать ли запрос, либо передаёт дальше;
🔘 Client: строит цепочку и отправляет запрос первому звену.


Пример


from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Optional, Any, Callable


class Handler(ABC):
def __init__(self, nxt: Optional["Handler"] = None):
self._next = nxt

def set_next(self, nxt: "Handler") -> "Handler":
self._next = nxt
return nxt # позволяет строить цепочку «в линию»

def handle(self, request: Any) -> Any:
# Базовая реализация: попытаться обработать здесь,
# иначе передать дальше.
result = self._handle_here(request)
if result is not None:
return result
if self._next:
return self._next.handle(request)
return None # никто не справился

@abstractmethod
def _handle_here(self, request: Any) -> Optional[Any]:
...


@dataclass
class HttpRequest:
path: str
headers: dict
user_id: Optional[int] = None
payload: Optional[dict] = None


class AuthHandler(Handler):
def _handle_here(self, req: HttpRequest) -> Optional[Any]:
token = req.headers.get("Authorization")
if not token:
# Нет токена — «решение на месте»: отклоняем и НЕ передаём дальше
return {"status": 401, "message": "Unauthorized"}
# валидируем (упростим) и ставим идентификатор
req.user_id = 42
return None # пропускаем дальше


class RateLimitHandler(Handler):
def __init__(self, check: Callable[[HttpRequest], bool], nxt: Optional[Handler] = None):
super().__init__(nxt)
self.check = check

def _handle_here(self, req: HttpRequest) -> Optional[Any]:
if not self.check(req):
return {"status": 429, "message": "Too Many Requests"}
return None


class RouterHandler(Handler):
def _handle_here(self, req: HttpRequest) -> Optional[Any]:
if req.path == "/me" and req.user_id:
return {"status": 200, "data": {"id": req.user_id}}
if req.path == "/ping":
return {"status": 200, "data": "pong"}
# Не мой маршрут — пропускаю дальше (если есть)
return None


class NotFoundHandler(Handler):
def _handle_here(self, req: HttpRequest) -> Optional[Any]:
# Терминальный обработчик: если дошли сюда — 404
return {"status": 404, "message": f"Route {req.path} not found"}


# Сборка цепочки
def build_pipeline() -> Handler:
auth = AuthHandler()
rate = RateLimitHandler(check=lambda r: True)
router = RouterHandler()
notfound = NotFoundHandler()

auth.set_next(rate).set_next(router).set_next(notfound)
return auth


if __name__ == "__main__":
pipeline = build_pipeline()
print(pipeline.handle(HttpRequest(path="/ping", headers={"Authorization": "Bearer x"})))
print(pipeline.handle(HttpRequest(path="/me", headers={"Authorization": "ok"})))
print(pipeline.handle(HttpRequest(path="/unknown", headers={"Authorization": "ok"})))
print(pipeline.handle(HttpRequest(path="/ping", headers={})))

BY Zen of Python


Share with your friend now:
tgoop.com/zen_of_python/4497

View MORE
Open in Telegram


Telegram News

Date: |

The initiatives announced by Perekopsky include monitoring the content in groups. According to the executive, posts identified as lacking context or as containing false information will be flagged as a potential source of disinformation. The content is then forwarded to Telegram's fact-checking channels for analysis and subsequent publication of verified information. During a meeting with the president of the Supreme Electoral Court (TSE) on June 6, Telegram's Vice President Ilya Perekopsky announced the initiatives. According to the executive, Brazil is the first country in the world where Telegram is introducing the features, which could be expanded to other countries facing threats to democracy through the dissemination of false content. Your posting frequency depends on the topic of your channel. If you have a news channel, it’s OK to publish new content every day (or even every hour). For other industries, stick with 2-3 large posts a week. The main design elements of your Telegram channel include a name, bio (brief description), and avatar. Your bio should be: Telegram channels fall into two types:
from us


Telegram Zen of Python
FROM American