模型视图控制器和复合视图

7

我正在尝试在Java Swing UI应用程序中遵循MVP(特别是被动视图)模式。

应用程序的基本设计类似于向导控件。屏幕分为两个主要部分:

  • 一个活动视图。
  • 一个静态导航栏,带有导航按钮。

用户可以使用按钮更改活动视图,但导航栏始终显示。

对于这种情况的建模,我有一堆不同的屏幕,每个屏幕都有自己的Presenter、View接口和View实现(使用JPanel)。然后我有一个Shell Presenter、View接口和View实现,使用一个JFrame。这个想法是,Shell将首先加载并始终显示,显示底部导航栏并留出空间给活动视图。Shell Presenter将允许设置当前活动屏幕,就像这样:

interface View {
}

class Presenter {
    View view;

    public Presenter(View view) {
        this.view = view;
    }

    public View getView() {
        return view;
    }

}

interface ShellView extends View {
    void setActiveView(View activeView);
}

class ShellPresenter extends Presenter {
    private ShellView shellView;

    public void setActivePresenter(Presenter activePresenter) { 
        shellView.setActiveView(activePresenter.getView());
    }
}

class ShellFrame implements ShellView {
    private JFrame frame;
    private JPanel activePanel;
    private JPanel navigationBar;

    public ShellFrame() {
        Container c = frame.getContentPane();
        c.add(activePanel);
        c.add(navigationBar);
    }

    public setActiveView(View activeView) {
        ???
    }
}

问题出在setActiveView方法上:我不确定如何将activeView设置为activePanel,因为View接口是通用的,并且不知道任何关于JPanels的内容。显然,我也不希望我的presenters知道关于JPanels的任何内容。

你最终解决了这个问题吗?这些答案都不是特别好。我刚刚发布了这个帖子:https://dev59.com/MHTYa4cB1Zd3GeqPzdg7 - durron597
3个回答

1

你能修改View的定义为:

interface View {
    JComponent getContainer();
}

这样每个视图都能轻松地获取视图内容?外壳不需要知道返回的JComponent实现细节。


1

你的View接口需要提供一些方法来获取在JPanel中可显示的内容:

interface View {
    Component getComponent();
}

然后在 ShellFrame 中(假设您使用 BorderLayout,就像我一样),您可以按以下方式设置视图:

public setActiveView(View activeView) {
   activePanel.add(activeView.getComponent(), BorderLayout.CENTER);     
}

1
问题在于你的 JFrameView,而不是每个单独的活动子视图。现在活动的视图是一个渲染工作,因此应该由 View 完成,而不是由 Presenter 完成。想象一下,如果你想要切换到一个不同的 View,它不仅有一个子视图可见,而且所有子视图都可见,但是活动的子视图具有不同的背景颜色。Presenter 只控制哪个子视图处于活动状态,但是 View 控制活动状态的含义。因此,你的任务不能完成,因为你试图做的工作本质上会破坏封装性。所以我会像这样做:
class PresenterManager {
    private Presenter activePresenter;
    private List<Presenter> allPresenters;

    IView view;

    PresenterManager(IView view) {
        this.view = view;
        view.subscribe(this);
    }

    void addPresenter(Presenter p) {
        allPresenters.add(p);
    }

    void setView(int index) {
        view.setView(index);
        activePresenter = allPresenters.get(index);
    }
}

class SwingView implements IView {
    List<SubView> allViews;
    SubView activeView;
    int lastIndex;

    public void setView(int index) {
        if(index != lastIndex) {
            activeView.setVisible(false);
            activeView = allViews.get(index);
            lastIndex = index;
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接