MVP:Presenter与Model的通信

3 投票
1 回答
4254 浏览
提问于 2025-04-16 03:08

我有一个关于MVP设计模式中模型和展示者之间沟通的设计问题,或者更准确地说,是它的派生形式——被动视图

假设我们有一个简单的图形界面作为例子:我有一个窗口,里面有一个列表,并且可以打开一个文件对话框来选择文件。一旦我完成选择,这个文件就应该被添加到列表中。

我的模型就是我打开的所有文件的集合。

我想到了一种简单的实现方式(伪代码):

方案A

class Model():
     def add(filename):
         # add file
         ...
         # return True if successful
         return True

class Presenter():
    # event from GUI
    def onFileOpen():
        filename = FileSelectorStuff()
        isFileAdded = model.add(filename)
        if isFileAdded:
            view.insertItem(filename)

在这种情况下,我知道文件已经被添加到模型中,因此我会相应地更新视图。

另一方面,我也可以先把文件添加到模型中,然后等待模型通知我它已经改变了,这样展示者就需要更新视图,像这样:

方案B

class Model():
     def add(filename):
         # add file
         ...
         # alert controller
         modelChanged(Type.FileAdded, filename)

class Presenter():
    # event from GUI
    def onFileOpen():
        filename = FileSelectorStuff()
        model.add(filename)

    # event from model
    def onModelChanged(type, filename):
        if type == Type.FileAdded:
            view.insertItem(filename)
        elif type == Type.FileRemoved:
            ...

在这两种情况下,实施效果都很好。但假设模型还监控文件,并且需要在某个文件被删除时通知展示者。那么我无论如何都需要这种onModelChanged()回调机制。

我的问题是:我应该把这两种更新视图的方法混合使用(A用于同步更新,B用于异步更新),还是应该像方案B所建议的那样,把所有内容集中在一个地方?

1 个回答

1

这个问题可能早就解决了,但我在搜索引擎上看到,所以我来分享一下我的看法:

用B。别混合使用。

如果你想为了效率而加入一些A的部分,你就得为模型准备两个方法:一个返回布尔值(也就是真或假),另一个用来发出事件。如果同步的Model.add方法发出事件,那么在这个方法调用期间,展示者中的事件处理程序就得忽略这些事件。这会让事情变得很麻烦。

不过,根据我对被动视图的理解,展示者应该负责更新模型,所以可以说它应该负责从模型中移除文件。这样就为只用A的解决方案铺平了道路。

我的最终建议: 用A,或者用B。别混合使用。

撰写回答