Добавление поведения REST к классу с флягой, кейс для чертежей? - PullRequest
11 голосов
/ 31 августа 2011

Я имею дело с приложением python, которое состоит из нескольких распределенных облегченных компонентов, которые взаимодействуют с использованием RabbitMQ & Kombu .

Компонент прослушивает две очереди и можетполучать несколько типов сообщений в каждой очереди.Подклассы могут переопределять способ обработки каждого типа сообщений путем регистрации пользовательских обработчиков.Все это прекрасно работает.

Теперь у меня есть дополнительное требование, чтобы у каждого компонента был базовый интерфейс REST / HTML.Идея заключается в том, что вы указываете своему браузеру на работающий компонент и получаете в реальном времени информацию о том, что он в данный момент делает (какие сообщения он обрабатывает, использование процессора, информация о состоянии, журнал и т. Д.)

Он должен быть легкимИтак, после некоторых исследований я остановился на Flask (но я открыт для предложений).В псевдокоде это означает:

class Component:
   Queue A
   Queue B
   ...
   def setup(..):
     # connect to the broker & other initialization

   def start(..):
     # start the event loop and wait for work  

   def handle_msg_on_A(self,msg):
     # dispatch a msg to a handler depending on the msg type

   def handle_msg_on_B(self,msg):
     ...

   ...

и добавление нескольких методов просмотра:

   @app.route('/')
   def web_ui(self):
      # render to a template

   @app.route('/state')
   def get_state(self):
      # REST method to return some internal state info as JSON

   ...

Однако, прикрепление веб-интерфейса пользователя к классу, подобному этому, ломает SOLID принципы и приносит проблемы с наследованием (подкласс может захотеть отображать больше / меньше информации).Декораторы не наследуются, поэтому каждый метод представления должен быть явно переопределен и переопределен.Может быть, использование mixin + отражение может работать как-то, но это кажется хакерским.

Вместо этого может сработать использование композиции: поместите веб-материал в отдельный класс, который делегирует маршруты URL-адресов фиксированному, предварительно определенному набору полиморфных методов во вложенном компоненте.Таким образом, компоненты остаются в неведении о Flask за счет некоторой потери гибкости (набор доступных методов исправлен).

Я обнаружил Чертежи Flask и Диспетчеризация приложений и похоже, что они могли бы предложить лучшее, более расширяемое решение.Тем не менее, мне еще предстоит обернуть голову вокруг них.

Я чувствую, что здесь отсутствует шаблон проектирования, и, надеюсь, кто-то с большим количеством фляг-фу или опытом с этим типом проблемы сможет прокомментировать.

1 Ответ

11 голосов
/ 31 августа 2011

В Flask 0.7 было тихо представлено что-то еще, что могло бы вас заинтересовать - Pluggable Views . Это основанные на классах , а не конечные точки, основанные на функциях - так что вы можете использовать метод dispatch_request для управления переходами состояний (переопределяя его только при необходимости).

Преимущество такого способа в отличие от использования Диспетчеризации приложений состоит в том, что вы получаете поддержку url_for во всем приложении (в отличие от необходимости жесткого кода в URL-адресах, которые пересекают границы приложения). решить, может ли это быть проблемой для вашего приложения.

В псевдокоде:

# File: Components.py
from flask.views import View

class Component(View):
    # Define your Component-specific application logic here

    dispatch_request(self, *url_args, **url_kwargs):
        # Define route-specific logic that all Components should have here.
        # Call Component-specific methods as necessary

class Tool_1(Component):
    pass

class Tool_2(Component):
    # Override methods here

# File: app.py
from flask import Flask
from yourapplication import Tool_1, Tool_2

app = Flask()

# Assuming you want to pass all additional parameters as one argument
app.add_url_rule("/tool_1/<path:options>", "tool1", view_func=Tool_1.as_view())

# Assuming you want to pass additional parameters separately
tool_2_view = Tool_2.as_view()
app.add_url_rule("/tool_2/", "tool2", view_func=tool_2_view )
app.add_url_rule("/tool_2/<option>", "tool2", view_func=tool_2_view)
app.add_url_rule("/tool_2/<option>/<filter>", "tool2", view_func=tool_2_view)

Вы можете добавлять чертежи в микс, если у вас есть ряд компонентов, которые все логически связаны друг с другом, и вы не хотите, чтобы не забудьте поставить /prefix перед каждым из них add_url_rule звонок. Но если у вас просто есть ряд компонентов, которые в основном независимы друг от друга, я бы использовал этот шаблон *.

*. С другой стороны, если они должны быть изолированы друг от друга, я бы использовал шаблон Application Dispatch, рекомендованный в документации.

...