views:

87

answers:

2

I'm writing a state machine like object. Looks like

Class A:

 vector<Actions> m_enter_actions;
 vector<Actions> m_exit_actions;

public:

  ClassA....
  ~ClassA

  SetEnterActions(vector<Actions> vector)
  SetExitActions(vector<Actions> vector)

Is this the best way to handle this? I wonder if I should have like

Class A:
  EnterActions m_exit_actions;
  ExitActions m_exit_actions;

public:

  ClassA....
  ~ClassA

  SetEnterActions(EnterActions& actions)
  SetExitActions(ExitActions& actions)

The EnterActions class would be a container with it's own vector of actions. That way the ClassA class doesn't need to manage raw vectors.

Any help is appreciated. I'm pretty bad at class design. Learning though :)

A: 

Use EnterActions and ExitActions if you think you'll ever need them to exhibit behaviors beyond normal vectors. Otherwise a vector is fine, imo.

Cogwheel - Matthew Orlando
+1  A: 

The signatures of the SetEnterActions and SetExitActions functions should be designed to prevent the caller from knowing how ClassA stores the Actions. Users of ClassA don't want to know whether ClassA stores them in a vector, or a deque, or a list, or in an EnterActions class, or whatever. They certainly don't want to have to package them up into whatever container ClassA stores them in.

My first inclination would be to allow the caller to provide an iterator, and also to allow the caller to add them one at a time with a function call:

template <typename InputIterator>
AddEnterActions(InputIterator first, InputIterator last);

AddEnterAction(const Action &action);

So, if the caller has them in a vector he calls AddEnterActions(vec.begin(), vec.end());. If he has them in an array, he calls AddEnterActions(arr, arr+size);. If he has some unusual means of generating them, he doesn't have to mess around putting them into a container and then adding them all at once, and he doesn't have to write an iterator class to generate them. He can just add them as he figures out what they are.

Meanwhile, if ClassA stores actions in a vector, then the implementation is just:

template <typename InputIterator>
AddEnterActions(InputIterator first, InputIterator last) {
    m_enter_actions.insert(m_enter_actions.end(), first, last);
}

AddEnterAction(const Action &action) {
    m_enter_actions.push_back(action);
}

If ClassA later wants to store them in something else, then you don't need to change any client code.

Where possible design the interface first, based on what callers want. Then worry about the implementation. You sometimes then have to go back and tweak the interface, when you discover that it's unimplementable or it demands that the class does something horribly inefficient. But usually not.

Steve Jessop