我认为您在概念上将“视图”与单个 GUI 组件绑定是错误的。在 MVC 模型中确实没有“子视图”这样的概念。
如果您有一个框架,例如,具有许多面板和子面板以及按钮等子组件,那么 整个事物 就是 MVC 中的视图/控制器接口。您的顶级框架(或一些封装类,也许您的 GUI 有很多框架,没关系)将提供到控制器(通过,比如说,事件)和视图(通过,比如说,监听器)的接口。您的 UI 的确切排列方式在其背后抽象。把你的整个 UI 想象成一个黑盒子。如何从内部组件分派/提供事件是 UI 实现的一部分,这很可能涉及事件链和委托等——但这不是视图/控制器所关心的。
所以你最终会得到类似(概念示例):
Model m = new Model();
View v = new View(m);
Controller c = new Controller(m);
MyFrame gui = new MyFrame(v, c);
然后:
public MyFrame (View v, Controller c) {
// register listeners to view, e.g.
v.addChangeListener(this /* or some other ui component */);
// send events to controller, e.g.
addActionListener(c /* or some interface that c provides */).
// or even:
deleteButton.addActionListener(new ActionListener(){
@Override public void actionPerformed (ActionEvent e) {
c.doDelete();
}
});
}
在理想情况下,您可以完全重新设计 GUI 的层次结构,拥有完全不同的组件树和组织,并且如果通过 GUI 传达的信息保持不变,视图和控制器也保持不变。
一旦你习惯了 MVC 模式,你可能会开始到处走捷径(例如,在许多情况下,视图和/或控制器只是事件的中间人,而 GUI 本身有时最终会封装整个控制器和视图概念,只剩下一个 GUI、一个模型和一堆事件侦听器——Swing 事件架构本身就是相当 MVC),并且边界可能会变得更加模糊。没关系。但是没有理由让视图或控制器必须知道 GUI 中的结构和对象树——即使在控制器/视图只是抽象概念而不是具体类的情况下。
有时 MVC 在使用 Swing 时会变得特别模糊,因为您最终会自然而然地以 MVC 方式做所有事情,因此当您尝试将 MVC 模式明确地强加到您的架构上时,您会想知道为什么不这样做'似乎没有太大变化(而且很难看到好处,因为你忘记了你已经在这样做了)。有时它更像是一种思考的方式,而不是一种具体的做事方式。
基本上,任何时候您的模型完全独立于您的 GUI,您正在使用 MVC 的某种化身。
编辑:我注意到您还用“观察者模式”标记了它并简要提到了它。值得注意的是,很多时候,为基于 Swing 的 GUI 显式实现观察者模式,至少在相对简单的应用程序中,只添加了一个冗余的抽象层,因为整个 Swing API 已经从根本上基于这种设计模式(它是整个事件 -> 监听子系统)。
我经常发现像下面这样的东西效果很好,到处使用所谓的观察者模式,其中控制器本质上只是事件侦听器的集合,例如:
public class Controller {
Model m;
public ActionListener getDeleteListener () {
return new ActionListener() {
@Override public void actionPerformed (ActionEvent e) {
m.deleteSomething();
}
};
}
}
然后 GUI 会执行以下操作:
public class GUI extends JFrame {
JButton deleteButton;
public GUI (View v, Controller c) {
deleteButton.addActionListener(c.getDeleteListener());
}
}
但是,有很多方法可以剥那只猫的皮。在那个例子中,一旦你熟悉了这个概念,如果合适的话,你可以走捷径,让 GUI 构造函数注册修改模型的侦听器。那么,如上所述,控制器就变成了一个抽象的概念。