2008-10-27 19 views
4

我有一系列的問題需要在創建GUI時將問題與邏輯分離。
以下是一個簡單對話框的簡單例子,該對話框使用「Humble Dialog」方法具有標籤和按鈕。按下按鈕應該在標籤上顯示一些文字。我已經使用了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(); 

現在這就是我通過遵循initial work on the Humble dialog by Feathers得到的。我從Fowler's implentation得到的方法是避免在MyView的構造函數中創建Presenter類的實例,而是將其作爲參數傳遞,以便生成代碼看起來像測試代碼。我個人喜歡我在這裏介紹的方法。

所以,

  • 打算把它與多重繼承(見我的MyView的類註釋)一起使用?
  • 應該將事件直接傳播給演示者還是應該在視圖中處理,以便調用相應的演示者動作(正如我在此處所做的,以避免必須使演示者成爲QObject才能處理UI事件)?
  • 還有其他的評論嗎?

回答

1

我通常使用相同的模式爲我的用戶界面在C#Winforms的東西。

你實際上並沒有真的在這裏做多重繼承。您繼承的其中一個類只是一個空的界面。這裏唯一的問題是C++不知道類和接口之間的區別。

我不認爲在這樣的視圖內創建演示者也有問題。這不是最可測試的設計,但是你可能不會去測試視圖,因爲如果你使用謙虛的對話框,沒有什麼可以測試的。或者,你可以通過添加第二個構造函數來注入演示者,而不是爲了測試目的而創建「窮人的DI」。

在C#中,我通常擁有根本不知道演示者的視圖,只是拋出事件而不是調用演示者。這增加了一些解耦,但在大多數情況下可能是矯枉過正的。

總的來說這是一個很好的實現。如果我永遠不得不寫一個帶有UI的C++應用程序,我會檢查這個帖子

1

對我來說看起來還行。但是我不會在IView-Interface中使用QString。如果可能的話,使用一些表示獨立類型。這樣,您可以更改GUI工具包,而不會影響程序邏輯和測試。只有在QString和std :: string或char *(我不知道......)之間進行轉換真的很痛苦時才保留QString。

+0

QString支持Unicode。只要您的字符串中沒有任何字符串具有Unicode字符,您爲轉換支付的所有費用就會有一點表現。 – 2008-10-29 10:20:22

2

當你用QObject做多重繼承時,繼承列表中的第一個類需要是QObject派生類。如果你打算爲你的班級添加信號和插槽,這只是嚴格要求,但無論如何都是很好的做法。所以,你的類聲明:

類MyView的:公共IVIEW,公開了QDialog {

需求,成爲這個代替:

類MyView的:公共QDialog的,公共的iView {

同樣,這隻會咬你,如果你曾經添加一個插槽或信號到「MyView」。

除此之外,我認爲這是一個很好的實現,雖然大量的對話的矯枉過正。 :)

我正在使用Fowler的MVP與Qt,它的工作正常。事情更容易測試(nUnit風格),但它是一個更復雜的國際海事組織。

+0

這完全正確!我被這個咬傷了。我會改變原來的帖子。 – 2009-11-01 21:40:45