2015-02-06 5 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; 
} 

은 내가 믿는 전형적인 전략 패턴을 것 나에게

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

뭔가를 컨텍스트 클래스를 구현하는 '사전 C++ (11)'방식을 감안할 때,이 디자인은 아니에요 Strategy에 대해 Context이 책임이 있는지 확인하고, 명확한 문서가 없으면 나쁜 일이 발생할 수 있습니다.

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 
} 

안전 포인터를 고려하여 안전 포인터를 삽입하고 ContextStrategy의 소유권을 부여하는 것이 바람직합니까?

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_; 
} 

물론이 디자인은 특히 동적으로들 Context에 주입 할 수 Strategy '을 할당, 그것의 자신의 문제를 소개합니다.

+1

왜'Context'는 * reference *에 의해'Strategy'를 취하지 않을까요? 그럼, 모호성! – Nim

답변

3

잘못하고 있습니다.

std::function에 비추어 볼 때 방금 작성한 모든 것이 완전히 폐기되었으며 std::function<int()>과 일부 람다를 사용해야합니다.

+0

람다를'std :: function'과 함께 사용할 필요가 없으므로 단지 그렇게 할 수 있습니다. 물론 혼동스러운 소유권 의미를 피할 수 있습니다. – Lionel

+0

귀하의 의견을 고맙게 생각하지만, 왜 내 질문에 답하는 것이 아니라 'std :: function'을 사용하는 것이 더 나은 방법인지 설명 할 수 있다면 좋을 것입니다. – Daniel

+0

@Daniel'std :: function'을 사용하면 더 이상 기본 포인터를 통해 인수를 전달하지 않아도되므로 소유권 문제를 피할 수 있습니다. 펑터를 감싸는'std :: function' 만 허용하면 메모리 관리를 대신 할 것입니다. – Lionel

0

Strategy 객체의 실제 목적이 다양한 Context 객체간에 공유되어야하는지 아니면 소유하고 있는지 여부에 따라 크게 달라집니다.

적어도 공유하거나 고유 한 ptr을 사용하면 의도를 명확하게 정의 할 수 있습니다. 다른 객체를 "보거나"(공유하지도 소유하지 않고 포인팅 된 객체가 가리키는 객체보다 오래 지속되지 않을 것이라고 확신하는 경우에만) "원시"포인터를 사용해야합니다.

2

디자인은 구현 자의 몫입니다.

예에서 비 C++ 11 포인터를 사용하여 전략 패턴을 여러 가지 방법으로 참조 할 수 있습니다.

는 귀하의 질문에 직접 대답하려면

예 당신은 전략 패턴으로 스마트 포인터를 사용해야합니다. 가능하면

당신은 스마트 포인터를 사용한다 :

추가 질문에 대답합니다.

스마트 포인터는 실제로 메모리 소유권 정책 측면에서 자체적으로 문서화되므로 "유용한 문서가 없다면"의 단점을 없애야합니다.당신은 사용자가 당신에게 메모리 소유권을 통과 할 것으로 예상되는 경우

  • unique_ptr
  • shared_ptr의 당신이 기대하는 경우 :

    당신이 당신의 상황에 맞는 클래스에 대한 노출 프로토 타입을 고려할 때, 당신은 당신의 기대에 어떤 사용자를 알 수 있습니다 같은 전략의 구현은 사용자가 메모리 관리 안전 무엇

을 처리하는 경우, 그것은 최대

  • weak_ptr를의 여러 소유자에 사용되는 너에게. 그러나 컨텍스트가 다른 컨텍스트와 구체적인 전략을 공유 할 수 있거나 컨텍스트 당 하나의 구체적인 전략이 있음을 사용자에게 알릴 수 있습니다.

    디자인 접근 방식으로, 전략/컨텍스트 (unique_ptr)를 사용하는 것이 좋습니다. 구체적인 전략은 고유/컨텍스트 인 일부 내부 변수를 갖게되고 거기에서 복잡해집니다.

  • 관련 문제