Search code examples
c++templatespolicy-based-design

Policy based design decisions


I have a class called Device that accepts two policies as far as I can see: StatePolicy and BehaviorPolicy.
The StatePolicy holds and manages the state of the device.
The BehaviorPolicy wraps the device driver that is written in C or C++.
Now I have two questions:

  1. How to coordinate between the state and the behavior policies?
  2. How do I store all the devices inside one container? Since Device<X, Y>'s type is different then Device<N, M> I cannot store them with one container.

EDIT 1: Here's some code to illustrate my problem:

class AbstractDevice
{
public:
  virtual ~AbstractDevice() {}

  virtual void performAction() = 0;
  virtual const string &getName() const = 0;
  //virtual void changeState(const ??? &_state) = 0;  If I put a template here it won't solve my problem
};

template<typename T>
class State
{
private:
  T state;
protected:
  typedef T StateType;
public:
  State() : state(1) {}

  const T &getState() { return state; }
  void setState(const T _state) { state = _state; }
};

template <class StatePolicy>
class LightbulbBehvior : protected StatePolicy
{
private:
  typedef StatePolicy SP;
public:
  virtual void performAction()
  {
    if ( SP::getState() )
      cout << "do stuff";
  }

  void changeState(const typename SP::StateType &_state)
  {
    setState(_state);
    performAction();
  }
};

template<class StatePolicy, template <class> class BehviorPolicy>
class Device : public AbstractDevice, public BehviorPolicy<StatePolicy>
{
private:
  string sName;
public:
  const string &getName() const { return sName; }
};

int main()
{
  AbstractDevice *d = new Device<State<int>, LightbulbBehvior>();
  d->changeState(5);
  return 0;
}

EDIT 2: This makes the code works with one downside, I have to maintain a list of all allowed state types. It looks a bit like the visitor pattern to me. Any thoughts?

class AbstractDevice
{
public:
  virtual ~AbstractDevice() {}

  virtual void performAction() = 0;
  virtual const string &getName() const = 0;
  virtual void changeState(const int &_state) = 0;
};

Thanks in advance,
Omer.


Solution

  • Here is the full design that works and does it's job pretty well at it:

    class AbstractState
    {
    public:
      virtual ~AbstractState() {}
    };
    
    class AbstractDevice
    {
    public:
      virtual ~AbstractDevice() {}
    
      virtual void performAction() = 0;
      virtual const string &getName() const = 0;
      virtual void changeState(const AbstractState &_state) = 0;
    };
    
    template<typename T>
    class State : public AbstractState
    {
    private:
      T state;
    protected:
      typedef T StateType;
    public:
      State() {}
      State(const T _state) : state(_state) {}
    
      const T &getState() const { return state; }
      void setState(const T _state) { state = _state; }
    };
    
    template <class StatePolicy>
    class LightbulbBehvior : protected StatePolicy
    {
    private:
      typedef StatePolicy SP;
    public:
      virtual void performAction()
      {
        if ( SP::getState() )
          cout << "do stuff";
      }
    
      void changeState(const typename SP::StateType &_state)
      {
        setState(_state);
        performAction();
      }
    };
    
    template<class StatePolicy, template <class> class BehviorPolicy>
    class Device : public AbstractDevice, public BehviorPolicy<StatePolicy>
    {
    private:
      string sName;
    
      typedef BehviorPolicy<StatePolicy> BP;
      typedef StatePolicy SP;
    public:
      const string &getName() const { return sName; }
    
      void performAction()
      {
        BP::performAction();
      }
    
      void changeState(const AbstractState &_state)
      {
        BP::changeState(((const SP &)_state).getState());
      }
    };
    
    int main()
    {
      AbstractDevice *d = new Device<State<int>, LightbulbBehvior>();
      d->changeState(State<int>(5));
      delete d;
      return 0;
    }
    

    @cjhuitt: Generally I think you are right but take a look and tell me what do you think.