Nie ma powszechnie uzgodnionych (tj. Defacto ) wytycznych projektowych dla MVC. Nie jest to wcale takie trudne, ale wymaga planowania na zajęciach oraz dużo czasu i cierpliwości.
Powodem, dla którego nie ma określonego rozwiązania, jest to, że istnieje wiele sposobów na MVC, wszystkie z ich zaletami i wadami. Bądź więc mądry i rób to, co najbardziej ci odpowiada.
Aby odpowiedzieć na twoje pytanie, faktycznie chcesz również oddzielić kontroler od widoku (abyś mógł używać tej samej logiki reguł biznesowych zarówno dla aplikacji Swing, jak i konsoli). W przykładzie Swing chcesz oddzielić kontroler od JWindow
i dowolnego widgetu w Swing. Sposób, w jaki kiedyś to robiłem (przed użyciem rzeczywistych frameworków), to stworzenie interfejsu dla widoku używanego przez kontroler:
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());
}
}
W przypadku tego rozwiązania podczas uruchamiania należy zarejestrować kontroler w widoku.
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
}
}
Dobrym pomysłem może być utworzenie kontenera IoC w celu wykonania całej konfiguracji.
W każdym razie w ten sposób możesz zaimplementować widoki tylko na konsolę, używając tych samych kontrolerów:
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
}
Zabawne jest to, jak obsługiwać zdarzenia. Zaimplementowałem to, pozwalając widokowi zarejestrować się w kontrolerze za pomocą interfejsu, odbywa się to za pomocą wzorca Observer (jeśli używasz platformy .NET, zamiast tego używałbyś programów obsługi zdarzeń). Oto przykład prostego „obserwatora dokumentów”, który sygnalizuje zapisanie lub załadowanie dokumentu.
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);
}
}
W ten sposób widok może się poprawnie zaktualizować, ponieważ subskrybuje aktualizacje dokumentu. Wystarczy zaimplementować DocumentObserver
interfejs:
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
}
// ...
}
Mam nadzieję, że te motywujące przykłady podadzą kilka pomysłów, jak to zrobić samodzielnie. Jednak zdecydowanie radzę rozważyć użycie frameworków w Javie, które wykonują większość rzeczy za Ciebie, w przeciwnym razie skończy się dużo kodu, który zajmuje dużo czasu, aby napisać. Istnieje kilka bogatych platform klienta (RCP), które można wykorzystać, które implementują niektóre podstawowe funkcje, które najprawdopodobniej będą potrzebne, takie jak obsługa dokumentów w całej aplikacji i wiele podstawowych czynności związanych z obsługą zdarzeń.
Z głowy mogę wymyślić kilka: RCP Eclipse i Netbeans .
Nadal musisz opracować dla siebie kontrolery i modele, ale właśnie dlatego używasz ORM. Przykładem może być Hibernacja .
Kontenery IoC są fajne, ale istnieją też ramy dla tego. Takich jak Spring (który zajmuje się także przetwarzaniem danych, między innymi).