Sign in to follow this  

Need advice with class design

This topic is 1955 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Greetings!

I am in need of some advice regarding my design.
Here's the basic jist of what i'm doing:

i have a hierarchy of objects that contain logic for the whole game.
the base class of the hierarchy is Action, which contains all data and members needed for every type of action to be able to run it's logic. it uses the template method pattern (Update() calls onUpdate(), which is pure virtual) to run some basic code before letting the derived class to take control.
[CODE]
class Action
{
public:
Action(String type);

void Update(TIME dt)
{
if(active)
onUpdate(dt);
}
void Init(ticpp::Element* xml)
{
if(xml == NULL)
return;
//default data extraction, like priority, timing etc

onInit(xml);
}

protected:
virtual void onUpdate(TIME dt) = 0;
virtual void onInit(ticpp::Element* xml) = 0;
};
[/CODE]

all derived actions define their own factory class, which uses the static registration trick, also called pluginable factories, if i'm not mistaken. they also hide their constructor, and define static Make() methods for each constructor variant. this way, i only have to write the code for a new action, define it's factory class, which registers itself during static initialization, and can create actions in two ways: via Derived::Make() and via a ActionFactory::Make() which in turn calls the corresponding derived factory.
[CODE]
class Accelerate : public Action
{
public:
static Accelerate* Make();
static Accelerate* Make(ticpp::Element* xml);

onInit(ticpp::Element* xml);
onUpdate(TIME dt);

private:
Accelerate();

class Maker : public ActionFactory
{
static Maker _self;
public:
Maker() : ActionFactory(Accelerate::_type) {}
Accelerate* Make(ticpp::Element* xml);
};
};
[/CODE]

now, in order to not replicate a LOT of code which differs in just the type of derived action, i made a template class ActionTemplate<T>, which defines the factory class as a template class too with the same type param.
[CODE]
template<class T>
class ActionTemplate : public Action
{
public:
ActionTemplate() : Action(_type) {}

static T* Make(ticpp::Element* xml)
{ T* ptr = T::Make(); ptr->Init(xml); return ptr; }

protected:
static String _type;

template<T>
class TMaker : public ActionFactory
{
static TMaker _self;
public:
Maker() : ActionFactory(ActionTemplate<T>::_type) {}
T* Make(ticpp::Element* xml) { return T::Make(xml); }
};
};
[/CODE]

ActionTemplate derives from Action, doesn't override any methods but adds some new ones, and all concrete derived actions inherit from it using the curiously recurring template pattern, like so:
[CODE]
class Accelerate : public ActionTemplate<Accelerate>
{
...
};
[/CODE]

so, here's the short of what i have: base class Action, from which ActionTemplate<T> is derived in order to save me from making a lot of type differing code. from ActionTemplate<T> are derived all others actions, in which i only define the logic (onUpdate(), onInit(), etc) of the concrete action.

and now here's the problem:
i need is a set of actions (for now i seem to need only 3, but...) that are composed of other actions, and update them in a certain order that differs from each container-action. this set of actions should implement an ActionContainer interface which has 2 methods: Add(Action*) and Remove(Action*). basically, i need actions that are dynamically composed of other actions.

i have looked into multiple inheritance, but it doesn't seem right.
i have looked at mixins, and am trying a solution similair to them (template<class T, class Base> class ActionTemplate : public Base {}), but it seems like a lot of problems might come out from it.
i cant inherit the ActionContainer interface from ActionTemplate<T> because the templated code wouldnt work (as can be figured from the code snippet above).
i was thinking about trying composition, but these container-actions ARE Actions, and ARE ActionContainers, so technically they should inherit from them, not compose them.

what i'm looking for, really, is any alternative method or advice to solving this problem of mine.
thank you in advance ^^

Share this post


Link to post
Share on other sites
[quote name='Strewya' timestamp='1343843784' post='4965261']
i was thinking about trying composition, but these container-actions ARE Actions, and ARE ActionContainers, so technically they should inherit from them, not compose them.
[/quote]

You might try to create a "MultiAction" class deriving from Action only -- MultiAction itself could implement the ActionContainer methods, there's no need to make that a separate interface unless you have other reasons for doing so (in which case, multiple inheritance is probably OK, because inheriting multiple interfaces is fine, its inheriting multiple concrete/partial classes that can cause problems).

This approach might or might not require you to implement a MultiActionTemplate<T>.

Share this post


Link to post
Share on other sites
i forgot to add a small bit of info.
base class Action has a static ActionPriorityQueue _defaultQueue member which is the default container to which actions add themselves when starting. but, they should also have a pointer to an ActionContainer* _queue, so things would work like this:
_defaultQueue is created as the concrete ActionPriorityQueue, so i can call Update() on it from the main loop. in the ctor of Action, _queue is set to &_defaultQueue, and there's a method setQueue(ActionContainer* q) to set the _queue var to any other container as needed. so actions add themselves like _queue.Add(this), which defaults to _defaultQueue, but can be set to anything.

one idea that i was thinking about is just to make the ActionContainer something like an ActionTemplate specialization, which is similair to Ravyne's suggestion.

Share this post


Link to post
Share on other sites
[quote name='Strewya' timestamp='1343843784' post='4965261']
i was thinking about trying composition, but these container-actions ARE Actions, and ARE ActionContainers, so technically they should inherit from them, not compose them.
[/quote]

I disagree with this. Given your current design, the class you're looking for has a primary purpose of being an Action that executes a set of Actions. Therefore, it is not an ActionContainer, it is (or should be) an Action that HAS an ActionContainer.


Then you can just query a getter method to get a pointer or reference to the ActionContainer, and pass that to your setQueue method.

i.e. something like this:

[CODE]
class SimpleActionContainer: public ActionContainer
{
public:
typedef std::vector<Action*>::iterator iterator;
typedef std::vector<Action*>::const_iterator const_iterator;

public:
void Add(Action* action){ _actions.push_back(action);}
void Remove(Action* action)
{
std::erase( std::remove( begin(), end(), action ) );
}

iterator begin(){ return _actions.begin(); }
iterator end(){ return _actions.end(); }
const_iterator begin() const { return _actions.begin(); }
const_iterator end() const { return _actions.end(); }

private:
std::vector<Action*> _actions;
};

class CompoundAction: public Action
{
public:
void onUpdate(TIME dt)
{
std::for_each( _actions.begin(), _actions.end(), [=]( Action* action ){ action->Update(dt); } );
}
void onInit(ticpp::Element* xml){}

ActionContainer* container() { return &_actions; }
const ActionContainer* container() const { return &_actions; }

private:
SimpleActionContainer _actions;
};
[/CODE] Edited by krippy2k8

Share this post


Link to post
Share on other sites
problem is, i'd have to create different containers alone, because the insertion might not be the same for every container type.
i implemented a PriorityQueue using a map and a list so it works for what i need to do. a plain List container doesn't have a wierd insertion algorithm as the PriorityQueue has. neither does a Stack.
i was thinking about whether or not i could somehow use composition, and the idea of having a container inside the action was the base for it, but it didn't sit good enough for the rest of the system.
in the end i'll settle for multiple inheritance, as i'm only using it for 3-4 classes in the whole system, inheriting from just 2 base classes, one of them being an interface.

but any other ideas of suggestions are welcome ^^

Share this post


Link to post
Share on other sites

This topic is 1955 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this