Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C+11 Strategy Pattern with state

An example of Strategy Pattern from the book, Head First Design Patterns, was written in C++ at [here]. I'm practicing to transform it into C++11 style according to Effective GoF Patterns with C++11 and Boost as showing below.

The Quack behavior:

struct Quack {
    static void quack()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

struct MuteQuack {
    static void quack()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

The Fly behavior:

struct FlyWithWings {
public:
    static void fly()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

struct FlyNoWay {
public:
    static void fly()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

The Duck hierarchy:

class Duck
{
public:
    typedef std::function<void(void)> QUACK;
    typedef std::function<void(void)> FLY;

public:
    Duck(const QUACK &q, const FLY &f)
        : m_Quack(q), m_Fly(f) {}

    virtual ~Duck()
    {
    }

    void perform_quack()
    {
        m_Quack();
    }
    void perform_fly()
    {
        m_Fly();
    }

protected:
    QUACK   m_Quack;
    FLY     m_Fly;

private:
    Duck(const Duck&) = delete;
    Duck& operator=(const Duck&) = delete;
};

class MallardDuck
    : public Duck
{
public:
    MallardDuck()
        : Duck(&Quack::quack, &FlyWithWings::fly)
    {
    }
};

class PaintedDuck
    : public Duck
{
public:
    PaintedDuck()
        : Duck(&MuteQuack::quack, &FlyNoWay::fly)
    {
    }
};

So far so good, the client works well.

int main()
{
    MallardDuck x1;
    x1.perform_quack();
    x1.perform_fly();

    PaintedDuck x2;
    x2.perform_quack();
    x2.perform_fly();

    return 0;
}

Now I would like to extend to a new class RubberDuck to Duck hierarchy, and the RubberDuck uses a new fly behavior FlyWithRocket which has a object state. As following:

A new Fly behavior:

class FlyWithRocket {
public:
    FlyWithRocket() : m_Energy(3) {}
    void fly()
    {
        if(m_Energy > 0)
        {
            fly_with_rocket();
            --m_Energy;
        }
        else
        {
            fly_out_of_energy();
        }
    }

private:
    void fly_with_rocket()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
    void fly_out_of_energy()
    {
        std::cout << __FUNCTION__ << std::endl;
    }

    unsigned int m_Energy;
};

A new Duck type:

class RubberDuck
    : public Duck
{
public:
    RubberDuck()
        : Duck(&MuteQuack::quack, std::bind(&FlyWithRocket::fly, std::ref(m_flyrocket)))
        , m_flyrocket()
    {
    }
private:
    FlyWithRocket m_flyrocket;
};

From now I'm wondering that the rule of the order of member initialization. The base Duck initializes before the member m_flyrocket, but note that the base Duck is initialized with binding m_flyrocket which is not initialized yet. As result as I run it in VS2013, this works without something wrong at run-time.

But is the code actually not safe? If not, how could I modify to a better design?

like image 845
cbel Avatar asked Apr 29 '14 09:04

cbel


People also ask

What is strategy and state design pattern?

State Pattern defines the “what” and “when” part of an Object. Example: What can an object when it's in a certain state. Strategy pattern defines the “How” part of an Object. Example: How a Sorting object sorts data. Order of State transition is well-defined in State pattern.

What is strategy design pattern in C++?

Strategy in C++ The Strategy pattern suggests: encapsulating an algorithm in a class hierarchy, having clients of that algorithm hold a pointer to the base class of that hierarchy, and delegating all requests for the algorithm to that "anonymous" contained object.

What is the state of a class C++?

State in C++ State is a behavioral design pattern that allows an object to change the behavior when its internal state changes. The pattern extracts state-related behaviors into separate state classes and forces the original object to delegate the work to an instance of these classes, instead of acting on its own.

What is the purpose of state pattern?

The state pattern is used in computer programming to encapsulate varying behavior for the same object, based on its internal state. This can be a cleaner way for an object to change its behavior at runtime without resorting to conditional statements and thus improve maintainability.


1 Answers

It's not safe, but it's unlikely to break unless you call m_Fly() from the base class constructor.

You can easily avoid this though, by either:

  1. giving the base class constructor a dummy or default-constructed std::function, and re-assigning m_Fly to your bind functor in the derived class constructor

    RubberDuck()
        : Duck(&MuteQuack::quack, std::function<void()>())
    {
        m_Fly = std::bind(&FlyWithRocket::fly, std::ref(m_flyrocket));
    }
    
  2. making FlyWithRocket a functor itself (just rename void fly to void operator()) and passing it by value instead of keeping a private member (it will be owned by the m_Fly function object, and you can access it via std::function::target<FlyWithRocket>() if you need)

    class FlyWithRocket {
    public:
        FlyWithRocket() : m_Energy(3) {}
        void operator() () {
    // ...
    
    RubberDuck()
        : Duck(&MuteQuack::quack, FlyWithRocket()) {}
    
like image 52
Useless Avatar answered Oct 27 '22 01:10

Useless