CDocument派生クラスがデータおよびそのシリアライズを提供し,データの表示をViewが担当するのがDoc-Viewアーキテクチャである.
このパターン自体には問題がないがMFCが提供するDoc-Viewアーキテクチャにはいささか問題がある.
このパターン自体には問題がないがMFCが提供するDoc-Viewアーキテクチャにはいささか問題がある.
基本となる機能は下記の通りである.
- CView派生クラスはGetDocumentでCDocument派生クラスを取得でき,データにアクセスできる.
- CDocument派生クラスはUpdateAllViewsで表示の更新を全てのCView派生クラスに通知できる.
- ウィザードでDoc-Viewアーキテクチャのサポートのチェックを外す.
- CWinApp派生クラスにCDocumentの代替となる独自のデータクラスを加える.
- CWinApp派生クラスにGetDataなどのデータクラスへのアクセス関数を追加する.
- CWinAppクラスのポインタはグローバル関数GetAfxAppで取得できる.これを実際のCWinApp派生クラスにダウンキャストすればよい.
- データからGUIへの通知にはBoost.Signals2などの汎用的なデリゲータライブラリを用いれば良い.
- その理由はデータクラスはビュークラスに依存すべきでないからである.さもなければ全てのビュークラスのヘッダーファイルをインクルードしその参照を手に入れる必要がある.
リファレンスのExample: Doc-Viewと対してかわりないので公開しておく.
- コンストラクタでModelBase派生クラス(CDocumen派生クラスの代替)をViewBase派生クラス(おそらくCWnd派生クラスと多重継承する)に渡す.
- ModelBase派生クラスはCWinApp派生クラスのメンバーにし,InitInstanceあたりで初期化する.
- 本手法では,新しいビュークラスを追加した場合でも必要なデータを手に入れることができるならば,ModelBase派生クラスを変更する必要がない.
class ModelBase { public: boost::signals2::connection Connect(const signal_t::slot_type &subscriber) { return mSignal.connect(subscriber); } protected: boost::signals2::signal<void ()> mSignal; }; class ViewBase { public: ViewBase(ModelBase& model) : mModel(model) { mConnection = mModel.Connect(boost::bind(&ViewBase::Update, this));} void Update() { UpdateInternal(); } protected: virtual void UpdateInternal() = 0; private: boost::signals2::connection mConnection; ModelBase& mModel; };
コメントをかく