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コンテナーはすべてがクールですが、これのためのフレームワークもあります。以下のような春(また、データは他のものの中だけでなくとして扱うん)。