2011-05-07 62 views
4

我高尚的追求是擺脫單身人士和靜態類的。C++擺脫單身的:替代仿函數和靜態方法

背景:
我具有以下結構:

  • Cmd的
    常見實例化的對象,它保存命令(串)的名稱,並且仿函數的任何類的作爲靜態方法一個指針。
    它通常在諸如Input,Console,Render等主要類中創建,並引用創建它的類中的方法,爲這些方法提供運行時口頭接口。
    CMDS也解釋參數在一個字符串數組,其中第一個參數是Cmd的名稱的形式,和用於被調用的靜態方法的所有連續字符串是直接參數。參數數量和參數數組存儲在Commander中,並在每個Cmd調用之前更改。
  • 指揮官
    指揮官用於解釋字符串的命令(其可以直接地來,或通過控制檯),它執行其存儲在緩衝器中作爲字符串Cmd的(通過調用它的算符)。

問題:
問題是,我試圖擺脫所有的靜態類(我現在變成了單身用於測試)的,而我使系統完全模塊化,鬆耦合。這反過來阻止了我有Cmds可以指向的靜態調用。

的第一反應是改變從一個typedef函子成一個模板類,這將存儲對象和方法,但它看起來很凌亂和複雜,我個人感到不舒服的打算:

Cmd::create("toggleconsole", Console::toggle); 

要:

Cmd::create("toggleconsole", new FunctorObject<Console>(&Console::get(), &Console::toggle)); 

最後Cmd的創作看起來很不起眼的和誤導性的,至於誰負責仿函數釋放的。

我也在將Cmd創建從靜態方法調用移動到Commander類中,所以它看起來像是commander.createCmd(「command_name」,...);而不是Cmd :: create(「command_name」,...);這是因爲Commander不再是靜態的(或單例),所以它處理的所有命令都必須屬於它。

我,但是,在一個完整的無所適從我的選擇/替代是允許的字符串進行登記的CMD,並保持鬆耦合命令發給指揮官。

我已經考慮過讓每一個主類從一個CmdListener類派生出來,它會在創建時用Commander註冊對象,然後在執行過程中將一個命令傳遞給所有註冊的對象,這些對象覆蓋了「onCmd(const Cmd &命令)」。

這留下了一些尚未解答的問題:Cmd如何繼承應該調用哪個類的方法?保持指針是沒有意義的,並且會受到高度模糊(如上所示)。另外,我想沒有重新解釋onCmd方法串,每類可能搞定CMD。

這是一個很多的信息,但沒有人有任何想法如何處理這個問題?

另外,我所有的類都必須知道Commander和Console對象,它們不再是單件/靜態的。到目前爲止,我已經將它們放置在一個Context對象中,並且像一個小膠囊一樣傳遞它。關於如何解決這些後單身殘餘問題的任何想法?

這個項目是我個人的工作,我打算在我的簡歷中使用它 - 因此,我不希望我的潛在僱主看到任何單身(我也不想向自己解釋爲什麼,因爲我可以向我自己證明他們並不是真正必要的)。

謝謝!

編輯:排版。

+1

這是一個有價值的目標!但是你可能不想太過分。就我個人而言,我是爲了從我工作的程序中刪除所有全局變量而設定的,但是全局常量(如果註冊階段結束時將是全局指揮官)不會打擾我。 – 2011-05-08 10:25:00

+0

好點!然而,我沒有提到的是,Commander通過發送到緩衝區的字符串輪詢命令,然後在每個主循環中執行一次。所以適當的客戶必須有相關的指揮官進行溝通。所描述的問題尚不存在,但一旦大多數組件不是全球性的(如果不是所有組件都是理想的),則可以預見到這一問題。 我會再次考慮你的建議,你可能還有一個有效的點! – Kaa 2011-05-08 18:39:23

回答

5

這是function類的工作。你可以在Boost中找到一個,或者在TR1或C++ 0x中找到。例如,它看起來像std::function<void()>。這通常與bind合作,如果您想參考以通用的方式轉換爲功能對象,而不是通過值來獲取它們,並且也可以在Boost,TR1或C++ 0x中找到,您將需要它。如果你有lambda函數,你也可以使用它們,這是一個很好的方法。

class Commander { 
    std::map<std::string, std::function<void()>> commands; 
public: 
    void RegisterCommand(std::string name, std::function<void()> cmd) { 
     commands[name] = cmd; 
    } 
    void CallCommand(std::string name) { 
     commands[name](); 
    } 
}; 
void sampleFunc() { 
    std::cout << "sampleFunc()" << std::endl; 
} 
struct sampleStruct { 
    int i; 
    void operator()() { 
     std::cout << i; 
     std::cout << "sampleStruct()() and the value of i is " << i << std::endl; 
    } 
}; 

int main() { 
    Commander c; 
    c.RegisterCommand("sampleFunc", sampleFunc); 
    sampleStruct instance; 
    instance.i = 5; 
    c.RegisterCommand("sampleStruct", instance); 
    std::string command; 
    while(std::cin >> command && command != "exit") { 
     c.CallCommand(command); 
    } 
    std::cin.get(); 
} 
+0

我真的很感激迴應! 跟進:請假設sampleStruct是一個sampleClass,並且包含多個方法。可以std ::函數指向一個特定的方法?目前它只指向一個重載()運算符,但其他方法呢? – Kaa 2011-05-08 00:13:46

+1

@Kaa結合'std :: function'和'std :: bind'來獲得你想要的。 – 2011-05-08 02:05:33

+1

@Kaa:正如Luc Danton所說,存在「std :: bind」來解決這個問題。 – Puppy 2011-05-08 11:38:34