powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Паттерн MVP
13 сообщений из 13, страница 1 из 1
Паттерн MVP
    #38841193
user199617
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Правильно ли я понимаю эту парадигму(святая троица)? Вот набросал небольшой пример на Python(2.7.9 + PyQt 4.8.xx).

Код: python
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
# -*- coding: utf-8 -*-
from PyQt4.QtCore import pyqtSignal
from PyQt4.QtGui import *
import sys

# Модель      
class Api(object):
    def login(self, username, password):
        return username == 'admin' and password == '1'

# Вид
class LoginForm(QDialog):
    # Почему работает только если объявить тут?
    submitted = pyqtSignal(unicode, unicode)
    success = pyqtSignal()
    fail = pyqtSignal(unicode)
     
    def __init__(self, parent=None):
        super(LoginForm, self).__init__(parent)
        self.setupUi()
        self.loginBtn.clicked.connect(self.onLogin)
        self.success.connect(self.onSuccess)
        self.fail.connect(self.onFail)
        
    def setupUi(self):
        self.setFixedSize(300, 150)
        self.setWindowTitle(u"Авторизация")
        self.vlayout = QVBoxLayout(self)
        self.errorLbl = QLabel(self)
        self.errorLbl.setWordWrap(True)
        self.errorLbl.setStyleSheet("color: red")
        # Не отображаем элемент.
        self.errorLbl.hide()
        self.vlayout.addWidget(self.errorLbl)    
        self.formLayout = QFormLayout(self)  
        self.usernameLbl = QLabel(self)
        self.usernameLbl.setText(u"Имя пользователя:")
        self.usernameLe = QLineEdit(self)
        self.formLayout.addRow(self.usernameLbl, self.usernameLe)
        self.passwordLbl = QLabel(self)
        self.passwordLbl.setText(u"Пароль:")
        self.passwordLe = QLineEdit(self)
        self.passwordLe.setEchoMode(QLineEdit.Password)
        self.formLayout.addRow(self.passwordLbl, self.passwordLe)
        self.vlayout.addLayout(self.formLayout)
        # Прижимаем форму кверху.
        spacer = QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)
        self.vlayout.addItem(spacer)
        # Прижимаем кнопку к правому краю.
        self.hlayout = QHBoxLayout(self)
        spacer1 = QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.hlayout.addItem(spacer1)
        self.loginBtn = QPushButton(self)
        self.loginBtn.setText(u"Логин")
        self.hlayout.addWidget(self.loginBtn)
        self.vlayout.addLayout(self.hlayout)
        
    def onLogin(self):
        username = unicode(self.usernameLe.text()).strip()
        password = unicode(self.passwordLe.text()).strip()
        
        if not username:
            self.showError(u"Введите имя пользователя.")   
        elif not password:
            self.showError(u"Введите пароль.")
        else:
            self.errorLbl.hide() 
            self.submitted.emit(username, password)
            
    def showError(self, text):
        self.errorLbl.show()
        self.errorLbl.setText(text)
            
    def onSuccess(self):
        self.close()
        
    def onFail(self, reason):
        self.showError(reason)
    
# Presenter
class App(object):
    def __init__(self):
        self.api = Api()
        self.app = QApplication.instance() or QApplication(sys.argv)
        self.loginForm = LoginForm()
        self.loginForm.submitted.connect(self.login)
        
    def login(self, username, password):
        if self.api.login(username, password):
            # Авторизовались и закрываем форму.
            return self.loginForm.success.emit()
        
        self.loginForm.fail.emit(u"Неправильное имя пользователя или пароль.")
        
    def run(self):
        self.loginForm.show()
        self.app.exec_()

def main():
    app = App()
    app.run()

if '__main__' == __name__:
    main()



В консоль будет срать ошибками, потому как в ручную код формы писал(а в кути я нуб).
...
Рейтинг: 0 / 0
Паттерн MVP
    #38841201
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user199617Правильно ли я понимаю эту парадигму(святая троица)? Вот набросал небольшой пример на Python(2.7.9 + PyQt 4.8.xx).нет, неправильно.
К MVP этот код никаким боком не относится.
...
Рейтинг: 0 / 0
Паттерн MVP
    #38841237
linux4gays
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White Owl, почему это не mvp? вид же ничего не знает ни о презентере, ни о модели? модель работает с данными, данные получаем через апи. можно пример расово верного мвп?
...
Рейтинг: 0 / 0
Паттерн MVP
    #38841266
GayLinuxPidOrg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
https://github.com/pahaz/Example-of-MVC-pattern-on-pure-Python/blob/master/appMVCv2.py нашел такой пример mvc не вижу особых различий. ну там есть роутер (у серверного приложения единственное событие на которое нужно реагировать это запрос). единственное что данные я проверяю в виде. модель у меня это просто данные апи возвращает ответ в виде json.
...
Рейтинг: 0 / 0
Паттерн MVP
    #38842122
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
linux4gaysWhite Owl, почему это не mvp? вид же ничего не знает ни о презентере, ни о модели? модель работает с данными, данные получаем через апи. можно пример расово верного мвп?Ты код смотрел?
Покажи мне в этом коде модель и презентера. Ну хотя бы одного из них.
...
Рейтинг: 0 / 0
Паттерн MVP
    #38842972
user199617
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White Owl, напиши мне пример
...
Рейтинг: 0 / 0
Паттерн MVP
    #38843204
user199617
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
...
Рейтинг: 0 / 0
Паттерн MVP
    #38845230
user199617
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А такой пример? Это MVC?

[quote wiki ]
Passive view[edit]

Passive view variant

* The controller is the only component which can communicate with the model and the view. There is no direct communication between view and model.
* The controller can send commands to the model to update the model's state (e.g., editing a document). It can also send commands to its associated view to change the view's presentation of the model (e.g., by scrolling through a document).
* The controller polls the model for updates.

Also called model-view-adapter
[/quote]

Код: python
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
# -*- coding: utf-8 -*-
from ui.login import Ui_LoginDialog
from PyQt4.QtGui import QApplication, QDialog

class Model:    
    users = [{"id": 1, "username": "Admin", "password": "1", "role": "admin"},
             {"id": 2, "username": "tester", "password": "test", "role": "user"}]
    
    def __init__(self, controller):
        self.controller = controller
    
    def login(self, username, password):
        for user in self.users:
            if user['username'] == username and user['password'] == password:
                return {"id": user['id'], "username": user['username'], "role": user['role']}
            
        return {"error": "Invalid username or password."}

class View(QDialog, Ui_LoginDialog):
    def __init__(self, controller):
        QDialog.__init__(self)
        self.setupUi(self)
        self.controller = controller
        self.errorLabel.setStyleSheet("color: red")
        self.errorLabel.hide()
        self.loginButton.clicked.connect(self.onLogin)
        
    def onLogin(self):
        self.errorLabel.hide()
        username = unicode(self.usernameEdit.text())
        password = unicode(self.passwordEdit.text())
        self.controller.login(username, password)
    
    def setErrorLabel(self, text):
        self.errorLabel.show()
        self.errorLabel.setText(text)
        
class Controller:
    def __init__(self):
        self.model = Model(self)
        self.view = View(self)
        self.view.show()
        
    def login(self, username, password):
        username = username.strip()
        password = password.strip()
        
        if not username:
            self.view.setErrorLabel(u"Введите имя пользователя.")
        elif not password:  
            self.view.setErrorLabel(u"Введите пароль.")
        else:
            result = self.model.login(username, password)
            
            if 'error' in result:
                self.view.setErrorLabel(result['error'])
            else:
                print u"Вы авторизовались как {username}.".format(**result)
                self.view.close()
        
if __name__ == '__main__':
    a = QApplication([])
    c = Controller()
    a.exec_()
...
Рейтинг: 0 / 0
Паттерн MVP
    #38845986
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user199617А такой пример? Это MVC?Нууу... Да, формально это MVC. Необходимые условия в этом коде уже есть.
С другой стороны, притягивание MVC для этой задачи это слегка... того... Из пушки по воробьям.
Для процедуры логина первый пример был намного лучше.

Вообще, на свете есть бесконечное количество задач которые можно реализовать через MVC/MVP/MVVM. Если у тебя есть переменная в памяти и значение этой переменной надо показать юзеру - это можно реализовать через MVC.
С другой стороны, в большинстве случаев это нафиг не нужно и будет только загромождать код и делать логику программы излишне замороченной (как в твоем втором примере).

Критерием для использовать или нет MVC (или его кузенов) может служить вопрос:
У тебя есть переменная. Эту переменную надо показывать одновременно в двух (или больше) местах на экране. В одном (или всех) из этих визуальных мест юзер может эту переменную редактировать. По изменению переменной в одном визуальном месте она должна обновится во всех остальных местах.
Если у тебя задача стоит именно так - тогда паттерн MVC, может быть полезным. Если у тебя нету множества одновременных отображений, то MVC не нужен.
...
Рейтинг: 0 / 0
Паттерн MVP
    #38846066
Фотография softwarer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlЕсли у тебя задача стоит именно так - тогда паттерн MVC, может быть полезным. Если у тебя нету множества одновременных отображений, то MVC не нужен.
При одновременном отображении MVC чаще всего не нужен. С избытком хватает MV, а C - дурацкая лишняя прокладка.

MVC становится реально нужным тогда, когда идёт отображение нескольких M на несколько V. Например, у меня он хорошо лёг в задачу типа Экселя. Когда с одной стороны есть модель данных, есть модель выделения (selection), есть модель атрибутов отображения (форматы-цвета-шрифты); с другой стороны есть сетка, есть поле редактирования текущей ячейки, есть список листов. На ряд операций они реагируют одинаково или сходно (например, удаление строки или очистка выделенной области). На некоторые операции они реагируют по-разному (например, атрибуты отрисовки из верхней строки копируются в новую, а данные - нет). Вот здесь MVC стал естественным и удобным решением.
...
Рейтинг: 0 / 0
Паттерн MVP
    #38846122
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
softwarerWhite OwlЕсли у тебя задача стоит именно так - тогда паттерн MVC, может быть полезным. Если у тебя нету множества одновременных отображений, то MVC не нужен.
При одновременном отображении MVC чаще всего не нужен. С избытком хватает MV, а C - дурацкая лишняя прокладка. А вот это уже вопрос по сложности обработки данных. Чем больше самих данных, чем сложнее правила обработки этих данных, чем больше разных "сопутствующих" аттрибутов у "реальных" данных. Тем больше полезность от Controller. Это если использовать именно MVC.
И да, в большинстве реальных задач controller действительно не нужен, чаще всего хватает MV пары. А если точнее, то правила изменения данных встроенные во view напрямую совпадают с правилами обработки данных в model. Например: строки это строки, числа это числа, дата это дата и тд... Тогда сontroller практически встроен во view и его как отдельного модуля может вообще не быть.
А если нужно проверять что дата в поле "от" раньше чем дата в поле "до".... А если в этом поле стоит галочка, то вон то поле должно быть заполнено... Вот тогда нужность в controller появляется очень быстро.


А если идти по пути MVP, то "прокладка" уже совершенно необходима.

И кстати, user199617, у тебя в во втором примере как раз MVP, а не MVC.
В классическом понимании этих паттернов Controller не влияет на то что отображается в View. В MVC View читает данные из модели напрямую, но обновляет через контроллер. А в MVP view запрашивает у presenter что отображать, а когда presenter считает нужным, он сам дергает view. Смотри на свой метод Controller::login. Ты там напрямую манипулируешь view... вот это и есть главный признак MVP.
Если хочешь превратить это в MVC, то добавь в модель проперть "результат последней попытки логина" и читай ее из view. Model::login будет кидать в View сигнал "есть обновления" и View будет обновляться отрисовывая результаты процедуры логина.

Еще можешь вот тут почитать:
http://nirajrules.wordpress.com/2009/07/18/mvc-vs-mvp-vs-mvvm/
Там хорошо расписаны отличия и особенности всех трех паттернов.
...
Рейтинг: 0 / 0
Паттерн MVP
    #38846240
user199617
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White Owl,

Я еще такой пример сделал:

Код: python
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
# -*- coding: utf-8 -*-
from PyQt4.QtGui import QApplication, QMainWindow
from PyQt4.QtCore import pyqtSignal
from ui.form import Ui_Form

class Model:
    km = 0
    miles = 0
    ratio = 1.609344
    
    def setKilometres(self, value):
        self.km = value
        self.miles = value / self.ratio
        
    def setMiles(self, value):
        self.miles = value
        self.km = value * self.ratio
        
class View(QMainWindow, Ui_Form):
    onKilometresChange = pyqtSignal([int, float])
    onMilesChange = pyqtSignal([int, float])
    
    def __init__(self):
        QMainWindow.__init__(self)
        self.setupUi(self)
        self.lineEdit_km.textEdited.connect(self._onKilometresChange)
        self.lineEdit_miles.textEdited.connect(self._onMilesChange)
        
    def setKilometres(self, value):
        self.lineEdit_km.setText( str( self.parseNumber(value) ) )
        
    def setMiles(self, value):
        self.lineEdit_miles.setText( str( self.parseNumber(value) ) )
        
    def _onKilometresChange(self):
        self.onKilometresChange( self.parseNumber( self.lineEdit_km.text() ) )
        
    def _onMilesChange(self):
        self.onMilesChange( self.parseNumber( self.lineEdit_miles.text() ) )
        
    def parseNumber(self, v):
        try:
            v = float(v)
        except:
            return 0
        
        if v % 1 == 0:
            return int(v)
        
        return round(v, 2)
        
class Presenter:
    def __init__(self, model, view):
        self.model = model
        self.view = view
        self.view.onKilometresChange = self.convertMiles
        self.view.onMilesChange = self.convertKilometres
        
    def convertMiles(self, km):
        self.model.setKilometres(km)
        self.view.setMiles(self.model.miles)
        
    def convertKilometres(self, miles):
        self.model.setMiles(miles)
        self.view.setKilometres(self.model.km)
        
if  __name__ == '__main__':
    a = QApplication([])
    m = Model()
    v = View()
    p = Presenter(m, v)
    v.show()
    a.exec_()



Соответствует ли он парадигме MVP? Может ли вид содержать ссылку на Presenter(self.presenter = presenter)?



Код формы генерированный:

Код: python
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file '.\form.ui'
#
# Created: Tue Dec 30 08:47:22 2014
#      by: PyQt4 UI code generator 4.11.3
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName(_fromUtf8("Form"))
        Form.resize(320, 240)
        self.widget = QtGui.QWidget(Form)
        self.widget.setGeometry(QtCore.QRect(10, 10, 205, 48))
        self.widget.setObjectName(_fromUtf8("widget"))
        self.formLayout = QtGui.QFormLayout(self.widget)
        self.formLayout.setMargin(0)
        self.formLayout.setObjectName(_fromUtf8("formLayout"))
        self.label = QtGui.QLabel(self.widget)
        self.label.setObjectName(_fromUtf8("label"))
        self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.label)
        self.lineEdit_km = QtGui.QLineEdit(self.widget)
        self.lineEdit_km.setObjectName(_fromUtf8("lineEdit_km"))
        self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.lineEdit_km)
        self.label_2 = QtGui.QLabel(self.widget)
        self.label_2.setObjectName(_fromUtf8("label_2"))
        self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.label_2)
        self.lineEdit_miles = QtGui.QLineEdit(self.widget)
        self.lineEdit_miles.setObjectName(_fromUtf8("lineEdit_miles"))
        self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.lineEdit_miles)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        Form.setWindowTitle(_translate("Form", "Перевод из километров в мили", None))
        self.label.setText(_translate("Form", "Километры: ", None))
        self.lineEdit_km.setText(_translate("Form", "0", None))
        self.label_2.setText(_translate("Form", "Мили:", None))
        self.lineEdit_miles.setText(_translate("Form", "0", None))
...
Рейтинг: 0 / 0
Паттерн MVP
    #38846842
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user199617Я еще такой пример сделал:
....
Соответствует ли он парадигме MVP? Нет. На этот раз у тебя получился MVC with passive view.

user199617Может ли вид содержать ссылку на Presenter(self.presenter = presenter)?В MVP - да. В MVP view напрямую вызывает presenter и просит его обработать действия юзера.
У тебя в коде view никого не вызывает вообще, только взводит сигналы, которые отслеживаются системой (вне твоей программы), и система будит Presenter (который на самом деле классический controller from MVC with passive view) и он уже напрямую взаимодействует со всеми.
...
Рейтинг: 0 / 0
13 сообщений из 13, страница 1 из 1
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Паттерн MVP
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]