GUI を作成するときにロジックからビューを分離するという問題に関して投稿する質問がたくさんあります。
以下は、「謙虚なダイアログ」アプローチを使用して、ラベルとボタンを持つ単純なダイアログに対して行うことの最小限の例です。ボタンを押すと、ラベルにテキストが表示されます。私は快適な C++ と Qt を使用しましたが、他のすべての聴衆が読むことができると思います。
いずれにせよ、言語の選択による副作用の可能性に興味があります (これを導入したいプロジェクトで C++ を使用しています)。
class IView {
public:
IView(){}
virtual ~IView(){}
virtual void showResult(const QString &text)=0;
};
class Presenter {
public:
Presenter(IView *view){
m_View = view;
}
~Presenter(){}
void buttonPressed(){
QString text;
// Evaluate text
m_View->showResult(text);
}
private:
IView *m_View;
}
// Multiple inheritance. Is this OK?
class MyView : public QDialog, public IView {
public:
MyView(){
m_Presenter = new Presenter(this);
m_Button = new QPushbutton(this);
m_Label = new QLabel(this);
// Ui event handled inside view but then directly
// propagated to the Presenter
connect(m_Button,SIGNAL(clicked()),this,SLOT(buttonPressed()));
}
~MyView(){
delete m_Presenter;
// Qt will automatically delete m_Button and m_Label;
}
void showResult(const QString &text){
m_Label->setText(text);
}
protected slots:
void buttonPressed(){
m_Presenter->buttonPressed();
}
private:
Presenter *m_Presenter;
QPushbutton *m_Button;
QLabel *m_Label;
}
class TestView : public IView {
public:
TestView(){}
~TestView(){}
void showResult(const QString &text){
m_LabelText = text;
}
QString getResult(){
return m_LabelText;
}
private:
QString m_LabelText;
}
// Test code
TestView view;
Presenter presenter(&view);
presenter.buttonPressed();
EXPECT_EQ(view.getResult(),"Expected Result");
// Procuction code
MyView view;
view.show();
これは、Feathers による Humble dialog の最初の作業に従って得たものです。Fowler の実装から得られるアプローチは、MyView のコンストラクターで Presenter クラスのインスタンスを作成することを避け、代わりにそれをパラメーターとして渡すことです。これにより、製品コードはテスト コードのように見えます。私は個人的にここで紹介するアプローチが好きです。
そう、
- 多重継承で使用することを意図していますか (MyView クラスの私のコメントを参照してください)?
- イベントをプレゼンターに直接伝達する必要がありますか、それともそれぞれのプレゼンター アクションを呼び出すビューで処理する必要がありますか?
- 他に注意点はありますか?