vendredi 6 février 2015

Should safe pointers be used in strategy pattern?

Given a typical strategy pattern



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


I believe the 'pre-C++11' way to implement a context class would be something like



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


To me, in this design it's not clear if Context should take responsibility for Strategy, and unless there is clear documentation stating otherwise, bad things might happen if it does



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
}


In light of safe-pointers, should it now be preferable to inject a safe pointer, and have Context take ownership of the Strategy?



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


or if Strategy can be shared amongst different Context?



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


This design of course introduces problems of it's own, in particular only dynamically allocated Strategy's can be injected into Context.


Aucun commentaire:

Enregistrer un commentaire