Нет общепринятых (то есть де-факто ) руководящих принципов проектирования для MVC. Это не так уж сложно сделать самостоятельно, но требует некоторого планирования занятий и большого количества времени и терпения.
Причина, по которой нет определенного решения, заключается в том, что существует множество способов сделать 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, которые делают большинство вещей за вас, иначе у вас в конечном итоге будет много стандартного кода, для написания которого потребуется много времени. Существует пара многофункциональных клиентских платформ (RCP), которые вы можете использовать, которые реализуют некоторые базовые функции, которые вам, скорее всего, необходимы, такие как обработка документов в рамках всего приложения и множество базовых обработчиков событий.
Есть пара, о которых я могу думать из своей головы: Eclipse и Netbeans RCP.
Вам все еще нужно разработать контроллеры и модели для себя, но именно поэтому вы используете ORM. Примером будет Hibernate .
Контейнеры IoC - это круто, но для этого тоже есть рамки. Например, Spring (который, помимо прочего, также обрабатывает данные).