Обновить индикатор выполнения - шаблон MVP - PullRequest
0 голосов
/ 25 сентября 2019

Я изучаю паттерн MVP, но с трудом следую принципам, чтобы обновить в реальном времени индикатор выполнения.Как я понимаю, Presenter проверяет, есть ли какое-либо обновление в Модели, а затем выводит результат, поэтому экземпляр Presenter в Модели не создается, только Presenter должен создавать экземпляры Модели и Представления.

Мой вопрос: как мне обновить индикатор выполнения, следуя принципу MVP?Я, конечно, мог бы вызвать Presenter.update_progress_bar (я, всего) из модели, но тогда это нарушило бы принцип MVP.

Вот минимальный рабочий пример:

PS: пока ям, используя CLI.

/ main.py

import modules

def main():
    modules.View(modules.Presenter).run()

if __name__ == "__main__":
    main()

/ modules / __ init __. py

from modules.Model.Model import Model
from modules.Model.progressbar import ProgressBar
from modules.View.View import View
from modules.Presenter.Presenter import Presenter

/ modules / Model / Model.py

class Model:
def __init__(self):
    pass

def long_process(self):
    import time
    for i in range(10):
        time.sleep(0.1)
        print("Update the progress bar.")
    return True

/ modules / Model / progressbar.py

# MIT license: https://gist.github.com/vladignatyev/06860ec2040cb497f0f3
import sys
class ProgressBar:
def progress(count, total, status=''):
    bar_len = 60
    filled_len = int(round(bar_len * count / float(total)))

    percents = round(100.0 * count / float(total), 1)
    bar = '=' * filled_len + '-' * (bar_len - filled_len)

    sys.stdout.write('[%s] %s%s ...%s\r' % (bar, percents, '%', status))
    sys.stdout.flush()

/modules / View / View.py

import sys
class View:
def __init__(self, presenter):
    self.presenter = presenter(self)

def run(self):
    self.presenter.long_process()

def update_progress_bar(self, msg):
    sys.stdout.write(msg)

def hide_progress_bar(self, msg):
    sys.stdout.write(msg)

def update_status(self, msg):
    print(msg)

/ modules / Presenter / Presenter.py

class Presenter:
def __init__(self, view):
    import modules
    self.model = modules.Model()
    self.view = view

def long_process(self):
    if self.model.long_process():
        self.view.update_status('Long process finished correctly')
    else:
        self.view.update_status('error')

def update_progress_bar(self, i, total):
    from modules import ProgressBar
    ProgressBar.progress(i, total)
    self.view.update_progress_bar(ProgressBar.progress(i, total))

def end_progress_bar(self):
    self.view.end_progress_bar('\n')

Я могdo:

class Model:
def __init__(self, presenter):
    self.presenter = presenter  # Violation of MVP

def long_process(self):
    import time
    for i in range(10):
        time.sleep(0.1)
        self.presenter.update_progress_bar(i, 10)  # Violation of MVP
        print("Update the progress bar.")
    return True

Но это неправильно, так как Модель теперь создает экземпляр Presenter.Есть предложения?

1 Ответ

1 голос
/ 25 сентября 2019

Используйте обратный вызов:

import time

class Model:
    def long_process(self, notify=lambda current, total: None):
        for i in range(10):
            time.sleep(0.1)
            notify(i, 10)  
        return True



class Presenter:
    def long_process(self):
        result = self.model.long_process(lambda c, t: self.update_progress_bar(c, t)):
        if result:
            self.view.update_status('Long process finished correctly')
        else:
            self.view.update_status('error')

Это позволит вашей модели быть независимой от кода клиента, но при этом позволит ей (я имею в виду модель) уведомлять вызывающего абонента.

В качестве стороныобратите внимание, что в вашем коде есть несколько вещей, которые совершенно непифонны:

1 / вам не нужно помещать каждый класс в отдельный модуль (на самом деле это считается антипаттерном в Python), и даже меньшево вложенных подмодулях (Python Zen: «квартира лучше, чем вложенная»).

2 / вам не нужно использовать классы, когда достаточно простой функции (подсказка: функции Python являются объектами ... на самом деле,все в Python является объектом) - у вашего ProgressBar класса нет состояния и только один метод, поэтому он может быть просто простой функцией (Python Zen: «просто лучше, чем сложнее»).

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

4 / имена модулей должны быть all_lower

...