views:

160

answers:

3

Hello, 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.

+1  A: 

I'm not sure about what you mean in the first question. Regarding the second one, you can create a DeviceBase class for the Device class template. Then, you can store pointers to this base class in containers.


class DeviceBase
{
  //...
};

template <class T1, class T2>
class Device : public DeviceBase
{
  //...
};
ltcmelo
Look at the code above.
the_drow
+1  A: 

As for the first question:

How to coordinate between the state and the behavior policies?

If you need to coordinate between the two policies, they are not orthogonal. If they aren't orthogonal, they won't lend themselves as well to the type of design you are doing. However, looking at the example code, I see that you already have the behavior relying on the state, so I don't know what the point of this question is...

As for the second question, ltcmelo has the correct answer, which is also embedded in your code. If you are looking for a way to keep templated classes in a generic container, that is your best way. In order to overcome the changeState problem, you'll need to make some generic function(s) to change the states how you want... like open, close, etc. If you can't make those functions, perhaps your code is too generic.

Caleb Huitt - cjhuitt
The code was an edit.See edit number 2 in a second.
the_drow
A: 

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.

the_drow