Non ci sono linee guida di progettazione comunemente condivise (ad esempio defacto ) per MVC. Non è così difficile da fare da soli, ma richiede un po 'di pianificazione sulle tue lezioni e molto tempo e pazienza.
Il motivo per cui non esiste una soluzione definitiva è perché ci sono molti modi per fare 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 disaccoppiare anche il controller dalla vista (in modo da poter utilizzare la stessa logica delle regole di business sia per un'app Swing che per l'app della console). Nell'esempio Swing, si desidera disaccoppiare il controller da JWindow
e qualsiasi widget in Swing. Il modo in cui ero solito fare (prima di usare i framework reali) è creare un'interfaccia per la vista che il controller usa:
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 fare tutto il setup per te.
In ogni caso, in questo modo puoi implementare le viste della sola console, usando 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 facendo sì che la vista si registrasse al controller usando un'interfaccia, questo è fatto usando il pattern Observer (se si sta usando .NET invece si useranno gestori di eventi). Ecco un esempio di un semplice "document observer", che segnala quando il 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 da quando si abbona agli aggiornamenti del documento. Tutto ciò che deve fare è implementare l'interfaccia 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
}
// ...
}
Spero che questi esempi motivanti ti diano alcune idee su come farlo da solo. Tuttavia ti consiglio caldamente di prendere in considerazione l'uso di framework in Java che fanno la maggior parte delle cose per te, altrimenti ti ritroverai con un sacco di codice boilerplate che richiede molto tempo per scrivere. Ci sono un paio di RCP (Rich Client Platform) che è possibile utilizzare per implementare alcune delle funzionalità di base più necessarie, come la gestione dei documenti a livello di applicazione e un sacco di gestione degli eventi di base.
Ci sono un paio che riesco a pensare dalla mia testa: Eclipse e Netbeans RCP's.
Devi ancora sviluppare controller e modelli per te stesso, ma è per questo che usi un ORM. Esempio sarebbe Hibernate .
I contenitori IoC sono fantastici, ma esistono anche strutture per questo. Ad esempio Spring (che gestisce anche la gestione dei dati, tra le altre cose).