I have a bunch of questions to post regarding the issue of separating the view from logic when creating a GUI.
The following is a minimal example of what I would do for a simple dialog that has a label and a button using the "Humble Dialog" approach. Pressing the button should show some text on the label. I have used C++ an Qt that I am comfortable with but I guess it is readable by all other audiences.
In any case I am interested in possible side effects because of the choice of language (I am using C++ in the project I am interested in introducing this).
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();
Now this is what I got by following the initial work on the Humble dialog by Feathers. The approach that I would get from Fowler's implentation would be to avoid creating the instance of the Presenter class in the constructor of MyView but pass it as a parameter instead so the production code would look like the test code. I personally like the approach I present here.
So,
- Is it meant to be used with multiple inheritance (see my comment in MyView class)?
- Should the events be propagated directly to the Presenter or should they be handled in the view that will call the respective presenter action (as I have done here to avoid having to make the Presenter a QObject so it can handle UI events)?
- Are there any other remarks?