我學習它周圍(如SOLID和依賴倒置原則特別)設計模式和東西,它看起來像我失去的東西:依賴倒置原則:試圖瞭解
繼DIP規則我應該能夠通過不在類中創建一個對象(組合),但發送對象引用/指針到類構造函數(聚合)使類更脆弱。但這意味着我必須在其他地方創建一個實例:所以聚合越靈活,另一個越脆弱。
請解釋我在哪裏錯了。
我學習它周圍(如SOLID和依賴倒置原則特別)設計模式和東西,它看起來像我失去的東西:依賴倒置原則:試圖瞭解
繼DIP規則我應該能夠通過不在類中創建一個對象(組合),但發送對象引用/指針到類構造函數(聚合)使類更脆弱。但這意味着我必須在其他地方創建一個實例:所以聚合越靈活,另一個越脆弱。
請解釋我在哪裏錯了。
你只需要遵循這個想法,直到它的邏輯結論。是的,你必須在其他地方創建實例,但是這可能不僅僅是在你的類的上一級的類中,它還需要被推出,直到只在應用程序的最外層創建對象。
理想情況下,您可以在一個地方創建所有對象,這稱爲composition root(例外情況是從工廠創建的對象,但工廠是在組合根中創建的)。具體取決於您正在構建的應用程序的類型。
這個地方可能最終會被「脆弱」,但你只能在一個地方改變的事情,爲了能夠重新配置您的應用程序,然後所有其他類都是可測試和配置的urable。
見this excellent answer(這是上面引述的)
是的,你需要在某個地方實例化類。如果你正確地遵循DIP,你將最終在一個地方創建所有的實例。我把這個地方稱爲課堂作文。閱讀我的博客,瞭解更多關於此主題的深入瞭解Here
您錯過的一個重要可能性是注入工廠,而不是課程本身。這樣做的一個好處是它可以讓你對實例的所有權變得更加清潔。注意代碼有點醜,因爲我明確地給出了組件的容器所有權。如果你使用shared_ptr
而不是unique_ptr
,那麼事情可能會有點整潔,但是所有權是不明確的。
所以開始的代碼看起來像這樣:
struct MyContainer {
std::unique_ptr<IFoo> foo;
MyContainer() : foo(new Foo()) {};
void doit() { foo->doit(); }
}
void useContainer() {
MyContainer container;
container.doit();
}
非出廠版本是這樣的
struct MyContainer {
std::unique_ptr<IFoo> foo;
template<typename T>
explicit MyContainer(std::unique_ptr<T> && f) :
foo(std::move(f))
{}
void doit() { foo->doit(); }
}
void useContainer() {
std::unique_ptr<Foo> foo(new Foo());
MyContainer container(std::move(foo));
container.doit();
}
出廠版本會是什麼樣子
struct FooFactory : public IFooFactory {
std::unique_ptr<IFoo> createFoo() override {
return std::make_unique<Foo>();
}
};
struct MyContainer {
std::unique_ptr<IFoo> foo;
MyContainer(IFooFactory & factory) : foo(factory.createFoo()) {};
void doit() { foo->doit(); }
}
void useContainer() {
FooFactory fooFactory;
MyContainer container(fooFactory);
container.doit();
}
IMO明確所有權在C++中的生命週期很重要 - 其一個C++身份的關鍵部分 - 它是RAII和許多其他C++模式的核心。