没有针对MVC的公认的(即defacto)设计指南。自己做起来并不难,但需要对您的课程进行一些计划,并花费大量时间和耐心。
没有确定的解决方案的原因是因为有多种方法可以进行MVC,各有利弊。因此,要对此保持精明,然后做最适合自己的事情。
为了回答您的问题,您实际上实际上也希望将控制器与视图分离(以便您可以对Swing应用程序和控制台应用程序使用相同的业务规则逻辑)。在Swing示例中,您希望将控制器与JWindow
Swing中的和其他小部件解耦。我以前做的方法(在使用实际框架之前)是为控制器使用的视图创建接口:
public interface PersonView {
void setPersons(Collection<Person> persons);
}
public class PersonController {
private PersonView view;
private PersonModel model;
public PersonController(PersonView view, PersonModel model) {
this.view = view;
this.model = model;
}
// ... methods to affect the model etc.
// such as refreshing and sort:
public void refresh() {
this.view.setPersons(model.getAsList());
}
public void sortByName(boolean descending) {
// do your sorting through the model.
this.view.setPersons(model.getSortedByName());
}
}
对于启动期间的此解决方案,您需要将控制器注册到视图中。
public class PersonWindow extends JWindow implements PersonView {
PersonController controller;
Model model;
// ... Constructor etc.
public void initialize() {
this.controller = new PersonController(this, this.model);
// do all the other swing stuff
this.controller.refresh();
}
public void setPersons(Collection<Person> persons) {
// TODO: set the JList (in case that's you are using)
// to use the given parameter
}
}
创建一个IoC容器来代替您完成所有设置可能是一个好主意。
无论如何,通过这种方式,您可以使用相同的控制器来实现仅控制台视图:
public class PersonConsole implements PersonView {
PersonController controller;
Model model;
public static void main(String[] args) {
new PersonConsole().run();
}
public void run() {
this.model = createModel();
this.controller = new PersonController(this, this.model);
this.controller.refresh();
}
public void setPersons(Collection<Person> persons) {
// just output the collection to the console
StringBuffer output = new StringBuffer();
for(Person p : persons) {
output.append(String.format("%s%n", p.getName()));
}
System.out.println(output);
}
public void createModel() {
// TODO: create this.model
}
// this could be expanded with simple console menu with keyboard
// input and other console specific stuff
}
有趣的部分是如何进行事件处理。我通过使用接口将视图自身注册到控制器来实现这一点,这是使用Observer模式完成的(如果使用.NET,则应使用事件处理程序)。这是一个简单的“文档观察器”的示例,该信号指示何时保存或加载文档。
public interface DocumentObserver {
void onDocumentSave(DocModel saved);
void onDocumentLoad(DocModel loaded);
}
// in your controller you implement register/unregister methods
private List<DocumentObserver> observers;
// register observer in to the controller
public void addObserver(DocumentObserver o) {
this.observers.add(o);
}
// unregisters observer from the controller
public void removeObserver(DocumentObserver o) {
this.observers.remove(o);
}
public saveDoc() {
DocModel model = model.save();
for (DocumentObserver o : observers) {
o.onDocumentSave(model);
}
}
public loadDoc(String path) {
DocModel model = model.load(path);
for (DocumentObserver o : observers) {
o.onDocumentLoad(model);
}
}
这样,由于视图正在订阅文档更新,因此视图可以正确更新。它要做的就是实现DocumentObserver
接口:
public class DocumentWindow extends JWindow
implements DocView, DocumentObserver {
//... all swing stuff
public void onDocumentSave(DocModel saved) {
// No-op
}
public void onDocumentLoad(DocModel loaded) {
// do what you need with the loaded model to the
// swing components, or let the controller do it on
// the view interface
}
// ...
}
我希望这些激励性的例子能给您一些有关如何自己做的想法。但是,我强烈建议您考虑使用Java框架来为您完成大部分工作,否则您最终将拥有大量的模板代码,而这些代码需要很长时间才能编写。您可以使用几个Rich Client Platform(RCP)来实现您最可能需要的一些基本功能,例如应用程序范围的文档处理和许多基本的事件处理。
我想到了几个:Eclipse和Netbeans RCP。
您仍然需要为自己开发控制器和模型,但这就是为什么要使用ORM的原因。例如Hibernate。
IoC容器很酷,但是也有一些框架。例如Spring(除其他功能外,它还执行数据处理)。