Non esistono linee guida di progettazione concordate (ovvero defacto ) per MVC. Non è del tutto difficile farlo da soli, ma richiede una certa pianificazione delle lezioni e un sacco di tempo e pazienza.
Il motivo per cui non esiste una soluzione definitiva è perché esistono diversi modi per eseguire MVC, tutti con i loro pro e contro. Quindi, sii intelligente e fai ciò che ti si addice meglio.
Per rispondere alla tua domanda, in realtà vuoi anche disaccoppiare il controller dalla vista (in modo da poter usare la stessa logica delle regole di business sia per un'app Swing che per l'app console). Nell'esempio di Swing si desidera disaccoppiare il controller da JWindow
e qualsiasi altro widget in Swing. Il modo in cui ero solito fare (prima di utilizzare i framework effettivi) è creare un'interfaccia per la vista utilizzata dal controller:
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());
}
}
Per questa soluzione durante l'avvio è necessario registrare il controller nella vista.
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
}
}
Potrebbe essere una buona idea creare un contenitore IoC per eseguire invece tutte le impostazioni.
Ad ogni modo, in questo modo è possibile implementare viste solo console, utilizzando gli stessi controller:
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
}
La parte divertente è come gestire gli eventi. Ho implementato questo lasciando che la vista si registrasse al controller usando un'interfaccia, questo è fatto usando il modello Observer (se usi .NET, invece, useresti i gestori di eventi). Ecco un esempio di un semplice "osservatore di documenti", che segnala quando un documento è stato salvato o caricato.
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);
}
}
In questo modo, la vista può aggiornarsi correttamente poiché si sta iscrivendo agli aggiornamenti del documento. Tutto quello che deve fare è implementare l' DocumentObserver
interfaccia:
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
}
// ...
}
Spero che questi esempi motivanti ti diano alcune idee su come farlo da soli. Tuttavia, ti consiglio vivamente di prendere in considerazione l'utilizzo di framework in Java che fanno la maggior parte delle cose per te, altrimenti finirai per avere un sacco di codice boilerplate che impiega molto tempo per scrivere. Esistono un paio di piattaforme Rich Client (RCP) che è possibile utilizzare per implementare alcune delle funzionalità di base di cui probabilmente avrete bisogno, come la gestione dei documenti a livello di applicazione e molta gestione degli eventi di base.
Ci sono un paio che mi viene in mente: Eclipse e Netbeans RCP.
Devi ancora sviluppare controller e modelli per te stesso, ma è per questo che usi un ORM. L'esempio sarebbe Hibernate .
I container IoC sono fantastici, ma ci sono anche framework per questo. Come Spring (che gestisce anche la gestione dei dati, tra le altre cose).