2015-02-06 33 views
2

給定一個典型的戰略格局應該在策略模式中使用安全指針嗎?

class Strategy 
{ 
public: 
    virtual int execute() const = 0; 
} 

class StrategyA : public Strategy 
{ 
public: 
    int execute() const override; 
} 

class StrategyB : public Strategy 
{ 
public: 
    int execute() const override; 
} 

我相信「前C++ 11」的方式來實現一個上下文類會是這樣的

class ContextRaw 
{ 
public: 
    ContextRaw(Strategy* the_strategy); 
    ~ContextRaw(); // Should this delete the_strategy_? 
    int execute() const; 
private: 
    Strategy* the_strategy_; 
} 

對我來說,在這樣的設計是不是如果Context應該對Strategy承擔責任,並且除非有明確的文件另有說明,否則可能會發生不好的事情

void trouble() 
{ 
    StrategyA a_concrete_strategy; 
    ContextRaw a_context(&a_concrete_strategy); // Oops, Context may try to delete stack variable 
} 

void more_trouble() 
{ 
    Strategy* a_concrete_strategy = new StrategyA; 
    ContextRaw* a_context  = new ContextRaw(a_concrete_strategy); 
    ContextRaw* another_context = new ContextRaw(a_concrete_strategy); 
    delete a_context; 
    std::cout << another_context.execute() << std::endl; // Oops, the_strategy is deleted 
} 

鑑於安全指針,現在應該注入一個安全指針,並讓Context獲得Strategy的所有權?

class ContextUnique 
{ 
public: 
    ContextUnique() = delete; 
    ContextUnique(std::unique_ptr<Strategy> the_strategy); 
    ~ContextUnique(); 
    int execute() const; 
private: 
    std::unique_ptr<Strategy> the_strategy_; 
} 

或者如果Strategy可以在不同的Context之間共享?

class ContextShared 
{ 
public: 
    ContextShared() = delete; 
    ContextShared(std::shared_ptr<Strategy> the_strategy); 
    ~ContextShared(); 
    int execute() const; 
private: 
    std::shared_ptr<Strategy> the_strategy_; 
} 

當然這樣的設計引入了它自己的問題,特別是只有動態分配Strategy的可注入Context

+1

爲什麼'Context'不能通過* reference *獲取'Strategy'?那麼,沒有歧義! – Nim 2015-02-06 11:31:38

回答

3

你做錯了。

根據std::function,您剛剛編寫的所有內容都已完全過時,您應該只使用std::function<int()>和一些lambda表達式。

+0

你不需要使用帶'std :: function'的lambda表達式,它只允許你這樣做。當然它也避免了混淆所有權語義。 – Lionel 2015-02-06 13:11:21

+0

儘管我很欣賞你的輸入,但如果你能解釋爲什麼使用'std :: function'是一個更好的方法,而不是隻是在強調我的問題,那將是很好的。 – Daniel 2015-02-06 13:47:53

+0

@Daniel使用'std :: function'將避免所有權問題,因爲您不再需要通過指向base的參數傳遞參數。只要允許'std :: function'包裝你的函數,它將代表你處理內存管理。 – Lionel 2015-02-06 14:12:24

0

它強烈依賴於Strategy對象的真正目的是什麼,它們是應該在各種Context對象之間共享還是由它們擁有。

至少當你使用共享或唯一的ptr時,你明確地定義了你的意圖。只有當您要「查看」其他一些對象時,才應該使用「原始」指針(您不共享也不擁有它 - 並且您確定指針對象不會超出指向的對象)。

2

設計由實施者決定。

請注意,在您的示例中,您將引用使用非C++ 11指針與Strategy模式搞砸的不同方式。

直接回答你的問題:

是的,你應該在戰略模式中使用智能指針。

要進一步回答問題:

您應該儘可能使用智能指針。

原因是智能指針在內存所有權策略方面實際上是自我記錄,因此您可以擺脫一些「如果沒有好文檔」的缺點。

考慮到你揭露你的Context類的原型,你可以告訴你有什麼期望用戶:

  • 的unique_ptr如果你希望用戶通過內存所有權轉讓給你
  • shared_ptr的,如果你希望的同樣的策略實現同時對多個業主使用
  • weak_ptr的,如果你希望用戶來處理內存管理

什麼是安全的,它是由 給你。但是,您可以告訴用戶Context可以與其他上下文共享其具體策略,或者每個Context有1個具體策略。作爲一種設計方法,我會建議使用1策略/上下文(如unique_ptr),因爲你的具體策略可能最終會有一些內部變量是唯一的/上下文的,事情會變得複雜。