Não há diretrizes de projeto comumente acordadas (ou seja, defacto ) para o MVC. Não é tão difícil fazê-lo você mesmo, mas exige algum planejamento em suas aulas e muito tempo e paciência.
A razão pela qual não existe uma solução definitiva é porque existem várias maneiras de fazer o MVC, todas com seus prós e contras. Portanto, seja esperto e faça o que melhor lhe convier.
Para responder sua pergunta, você também deseja desacoplar o controlador da visualização (para poder usar a mesma lógica de regra de negócios para um aplicativo Swing e no aplicativo do console). No exemplo do Swing, você deseja desacoplar o controlador do JWindow
e de qualquer widget no Swing. O jeito que eu costumava fazer (antes de usar estruturas reais) é criar uma interface para a visualização que o controlador 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());
}
}
Para esta solução durante a inicialização, você precisa registrar o controlador na visualização.
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
}
}
Pode ser uma boa ideia criar um contêiner de IoC para fazer toda a configuração para você.
De qualquer forma, dessa maneira, você pode implementar visualizações somente do console, usando os mesmos controladores:
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
}
A parte divertida é como lidar com eventos. Eu implementei isso permitindo que a visualização se registrasse no controlador usando uma interface, isso é feito usando o padrão Observer (se você estiver usando o .NET, você usaria manipuladores de eventos). Aqui está um exemplo de um "observador de documentos" simples, que sinaliza quando o documento foi salvo ou carregado.
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);
}
}
Dessa forma, a exibição pode se atualizar adequadamente, pois está assinando as atualizações do documento. Tudo o que precisa fazer é implementar a DocumentObserver
interface:
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
}
// ...
}
Espero que esses exemplos motivadores lhe dê algumas idéias sobre como fazer você mesmo. No entanto, eu recomendo fortemente que você considere o uso de estruturas em Java que fazem a maioria das coisas para você; caso contrário, você acabará tendo muito código clichê que demora muito tempo para escrever. Existem algumas RCP (Rich Client Platforms) que você pode usar para implementar algumas das funcionalidades básicas que você provavelmente precisa, como manipulação de documentos em todo o aplicativo e muita manipulação de eventos básicos.
Há alguns que consigo pensar na minha cabeça: Eclipse e RCP do Netbeans .
Você ainda precisa desenvolver controladores e modelos para si mesmo, mas é por isso que você usa um ORM. O exemplo seria o Hibernate .
Os contêineres de IoC são legais, mas também existem estruturas para isso. Como o Spring (que também lida com dados, entre outras coisas).