Skip to main content
gamedev.net
🔒 Locked

class design problem

Started by ghostd0g Jan 15, 2007 at 9:38 AM 4 replies 750+ views
Original Post
ghostd0g
ghostd0g
hi there. my design started out like that: class A holds a pointer and the pointed-to data could be changed by different controllers. class A holds n controllers (concrete controller classes). controllers can be registered, unregistered and updated. controllers change that member of class A over a certain time, so soon i needed a functionality where controllers can unregister themselves after the time is over. i didn't want the controller classes to know about class A (to ensure loose coupling) so i introduced a boolean "shouldDie" flag. class A checks that flag before every controllersUpdate() if a controller should be deleted and in case deletes them. but now i need one of the controllers to not only update the pointed-to data but also the pointer itself when the before mentioned time is over. eventually other controllers should be informed of that pointer change. is there an elegant way (read: any pattern) to accomplish that or do i finally need to let the controller know about class A? thanks in advance! [Edited by - ghostd0g on January 15, 2007 10:23:17 AM]
ghostd0g
ghostd0g
1) C++
2) sorry, i had to update my problem description.

i could provide code but i'm not sure if this would not overcomplicate things.
hmm, anyway i'm trying to provide a basic version.
mikeman
mikeman
I could look at some code, but anyway. If we assume we have a function like:

void Controller(char* data);

and we want Foo to be able to change the pointer itself, then we pass it as a reference:

void Controller(char* &data);

If you're doing what I think you're doing(passing a private member into another class/function that changes it), then I'm not sure I really like it. That means that the controller is able to bring the class A into an invalid state(by,say,setting the pointer to NULL or an invalid value). Anyway, meybe you could rethink if you can achieve your goal in any safer way.
Mouseee
Mouseee
The way I see it, there's no need to let controllers know about class A. You need to wrap the pointer somehow, here are some ideas:

class A{ Data D; Controllers...  A : Controller1(D), Controller2(D), ...}class Data{ data_ptr* p;}class Controller{ Data& D; Controller(Data & d) : D(d) update() // uses/modifies D.p}


Or you could make the pointer change via the call to controllers' update:

class A{ data_ptr* p; A::controllersUpdate() {  for each Controller C  {   p = C.update(p);  } }}class Controller{ data_ptr* update(data_ptr* p) // uses/changes and returns p}


You should probably also consider somehow promoting that one controller that may change the pointer, maybe implement its functionality inside A instead? What you really need depends on the details of your case.
ghostd0g
ghostd0g
thanks Mouseee! you more or less nailed it.
i can see that your 2 methods work fine. i especially like method 2 because it doesn't need another level of indirection (adapter class). never thought of that.

although i think i will eventually run into problems with my pointers in vectors approach (see code below) and i won't be able to use the STL'ish foreach-bind2nd-mem_fun combo ;)

anyway, finally here is some of my code. i hope it is not too confusing ...

class B;	//uninteresting for nowclass A{private:	std::vector<AbstractController*>  controllers;		std::vector<B*>                   objects;	B*                                currentObject;	//should always point to the active objectpublic:	void UpdateControllers(float dt)	{        //delete flagged controllers        std::for_each(controllers.begin(), controllers.end(), delAndNullifyFlaggedController);		        //erase nullified pointers from container        controllers.erase(std::remove(controllers.begin(), controllers.end(), static_cast<AbstractController*>(0)), controllers.end());				//update all remaining controllers        ext::Foreach(controllers, std::bind2nd(std::mem_fun<void, AbstractController>(&AbstractController::Update), dt));	}	//Register, Unregister, ...};/* virtual controller base class */class AbstractController{public:    AbstractController(B* object_)        : object(object_)    {}		virtual void Update(float dt) = 0;		bool ShouldDie() const { return shouldDie; }	protected:	B* object;};/* WORKS, but is the flag-method elegant? */class SomeController : public AbstractController{public:	SomeController(B* object_) ...		void Update(float dt)	{		//do something on *(this->object) aka *(A::currentObject)				if (someCondition)		{					shouldDie = true			return;		}	}};class ProblematicController : public AbstractController{public:	ProblematicController(B* object_) ...		void Update(float dt)	{		//do something on *(this->object) aka *(A::currentObject)				if (someCondition)		{			//MISSING: should let this->object aka A::currentObject point to somewhere else in A::objects						shouldDie = true			return;		}	}};



btw, any thoughts on the controller-self-unregistering problem? or is the shouldDie-flag-method ok?

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.