How should an object that uses composition set its composed components?
- by Casey
After struggling with various problems and reading up on component-based systems and reading Bob Nystrom's excellent book "Game Programming Patterns" and in particular the chapter on Components
I determined that this is a horrible idea:
//Class intended to be inherited by all objects. Engine uses Objects exclusively.
class Object : public IUpdatable, public IDrawable {
public:
Object();
Object(const Object& other);
Object& operator=(const Object& rhs);
virtual ~Object() =0;
virtual void SetBody(const RigidBodyDef& body);
virtual const RigidBody* GetBody() const;
virtual RigidBody* GetBody();
//Inherited from IUpdatable
virtual void Update(double deltaTime);
//Inherited from IDrawable
virtual void Draw(BITMAP* dest);
protected:
private:
};
I'm attempting to refactor it into a more manageable system. Mr. Nystrom uses the constructor to set the individual components; CHANGING these components at run-time is impossible. It's intended to be derived and be used in derivative classes or factory methods where their constructors do not change at run-time. i.e. his Bjorne object is just a call to a factory method with a specific call to the GameObject constructor.
Is this a good idea? Should the object have a default constructor and setters to facilitate run-time changes or no default constructor without setters and instead use a factory method?
Given:
class Object {
public:
//...See below for constructor implementation concerns.
Object(const Object& other);
Object& operator=(const Object& rhs);
virtual ~Object() =0;
//See below for Setter concerns
IUpdatable* GetUpdater();
IDrawable* GetRenderer();
protected:
IUpdatable* _updater;
IDrawable* _renderer;
private:
};
Should the components be read-only and passed in to the constructor via:
class Object {
public:
//No default constructor.
Object(IUpdatable* updater, IDrawable* renderer);
//...remainder is same as above...
};
or Should a default constructor be provided and then the components can be set at run-time?
class Object {
public:
Object();
//...
SetUpdater(IUpdater* updater);
SetRenderer(IDrawable* renderer);
//...remainder is same as above...
};
or both?
class Object {
public:
Object();
Object(IUpdater* updater, IDrawable* renderer);
//...
SetUpdater(IUpdater* updater);
SetRenderer(IDrawable* renderer);
//...remainder is same as above...
};