MVP中View和Presenter的关系

问题描述 投票:0回答:1

我有一个使用 x11 lib 来绘制一些用户界面的应用程序。现在我尝试用 MVP(模型-视图-演示者)模式重构它,但叠加了有关视图-演示者部分的一些细节。例如:我有一个左/右箭头键按下事件,通过该事件,我需要按视图上的元素(如浏览器中的选项卡)循环。现在这个事件只是从View流到Presenter,然后Presenter选择下一个要激活的元素并将其推回ui。但是(!)要选择下一个元素,我需要在 BEGIN 和 END 上有一个迭代器(C ++,在其他语言中可能只是查看对象列表末尾的引用/索引),它导致有一种特殊的方法来获取它在IView界面中,看起来不太清楚。在视图中执行按键,选择下一个元素,然后通知演示者当前活动元素不是更好吗?

我读过很多相关文章,并使用此模式检查了存储库。但还是看不懂:(

伪代码:


class IView {

public:

virtual Element* firstElement();

virtual Element* lastElement();

};

class Presenter {

public:

void onRightKeyPressed() {

    if(!currentElement) {

        currentElement = view->firstElement();

    } else {
        currentElement->resetActive();

        ++currentElement;

       if(currentElement == view->lastElement()) {
           currentElement = view->firstElement():
       }
    }
    currentElement->setActive();

}

private:

IView* view;

Element* currentElement;

};

与类似的东西

class IView {
public:
    // Notify the presenter about the currently active element
    virtual void notifyElementActivated(Element* element) = 0;
    
    // Handle arrow key press event and select the next element
    virtual void handleRightKeyPressed() = 0;
};

class Presenter {
public:
    void onRightKeyPressed() {
        view->handleRightKeyPressed();
    }
    
    // Receive the notification from the view about the currently active element
    void notifyElementActivated(Element* element) {
        // React to the active element change
    }
    
private:
    IView* view;
};

class View : public IView {
public:
    void handleRightKeyPressed() override {
        if (!currentElement) {
            currentElement = firstElement();
        } else {
            currentElement->resetActive();
            
            ++currentElement;
            
            if (currentElement == lastElement()) {
                currentElement = firstElement();
            }
        }
        
        currentElement->setActive();
        // Notify the presenter about the currently active element
        notifyElementActivated(currentElement);
    }
    
    void notifyElementActivated(Element* element) override {
        presenter->notifyElementActivated(element);
    }
    
private:
    Presenter* presenter;
    Element* currentElement;
};

我期待这个案例有更明确的解决方案!

design-patterns view interface mvp presenter
1个回答
0
投票

您的问题有不同的“正确”解决方案。选择哪一个取决于 Element 对象是什么、活动元素控制的 Presenter 逻辑有多少(如果有)以及该逻辑的外观。

如果“Element”只是一个哑标签页,并且 Presenter 几乎不包含依赖于活动元素的逻辑,则可以让 View 完全负责保存当前元素和前进/后退逻辑。为此,您的第二个解决方案看起来是一个好的开始。然而,虚拟方法

IView::notifyElementActivated
似乎已经过时了(如果演示者能够通知视图有关激活的信息,则您需要它,我不知道您是否真的需要它)。

此外,您的代码没有给出任何线索是否确实需要

Presenter::notifyElementActivated
,或者方法
View::getCurrentElement
是否足够。

在您的第一个解决方案中,当前元素的管理是演示者的一部分,只要视图没有自己的“活动页面/元素”管理,这就可以了,这可能会偏离演示者。您写下了您的担忧:

但是(!)要选择下一个元素,我需要在 BEGIN 和 END(c++,在其他语言中可能只是结尾处的引用/索引 查看对象的列表)它导致有一个特殊的方法 在IView界面中获取,看起来不太清楚。

那么,为什么不这样设计你的 IView 界面呢?

class IView {
public:
    virtual const vector<Element> &elements();
}

我还建议将 Presenter 中的

onRightKeyPressed()
重命名为
gotoNextElement()
。您的视图应该有一个事件处理程序
onRightKeyPressed()
,它调用
presenter->gotoNextElement()
- 哪些键确切地导致向前或向后导航是演示者不应该关心的事情。

© www.soinside.com 2019 - 2024. All rights reserved.