在C++中,我經常使用RAII風格的對象來使代碼更加可靠,並將它們分配到堆棧上以使代碼更具性能(並避免bad_alloc)。堆棧分配的RAII對象與DI原理
但是在堆棧上創建一個具體類的對象違反了依賴倒置(DI)原則並且防止嘲笑這個對象。
考慮下面的代碼:
struct IInputStream
{
virtual vector<BYTE> read(size_t n) = 0;
};
class Connection : public IInputStream
{
public:
Connection(string address);
virtual vector<BYTE> read(size_t n) override;
};
struct IBar
{
virtual void process(IInputStream& stream) = 0;
};
void Some::foo(string address, IBar& bar)
{
onBeforeConnectionCreated();
{
Connection conn(address);
onConnectionCreated();
bar.process(conn);
}
onConnectionClosed();
}
我可以測試IBar::process
,但我也想測試Some::foo
,而無需創建真正的Connection對象。
當然,我可以使用工廠,但它會使代碼顯着複雜化並引入堆分配。
此外,我不喜歡添加Connection::open
方法,我更喜歡構造完全初始化和功能齊全的對象。
我會做Connection
類型的模板參數Some
(或foo
如果提取出來作爲一個免費的功能),但我不知道這是正確的方式(模板看起來像一個黑色的魔法很多人,所以我更喜歡使用動態多態)
模板不應該對於或多或少能勝任的C++程序員來說是魔法,我沒有理由避免它們。另外我不認爲堆分配是昂貴的(這當然取決於你編寫的軟件),所以我沒有理由避免它(當用於智能指針時)。 –
@亞歷B:有種理由避免它們,儘管我同意這不是因爲它們是「黑魔法」。這是因爲如果所有東西都是通過模板參數注入的,那麼您編寫的所有東西都是模板,您的庫只是標頭,並且在編譯或分發方面可能會非常麻煩。儘管如此,我想小心你可以單元測試只有頭文件的庫,然後從它構建一個只包含應用程序需要的實例的TU。 –
RAII和DI在一起工作很好,所以標題是誤導性的,你的問題是堆棧分配與DI。 –