I guess I've asked a few similar questions before, but I was beating around the bush. I think this is the real problem that I can't quite lay to rest.
I'm dealing with a third party library, and there's an object that can't create itself, b2Body. The b2World has to instantiate it. I personally don't like this design pattern very much; I think the b2Body should be able to exist independently of the world, and then be added to the world when needed. Anyway, I've wrapped b2Body with my own class class, Body, because I need to add some extra stuff to it anyway. Similarly, I have a World wrapper. Now I figure I have 3 options:
Body's constructor takes a pointer to World so that it can be fully instantiated (calls b2World::CreateBody somewhere inside) -- i.e. have a constructor like Body *b = new Body(world_ptr)Body to some World::CreateBody method like how the library already does it -- i.e. Body *b = world.CreateBody(params);b2Body so that you can use it however you want, and then after you add it to the world it will 'switch over' to use the b2Body data -- i.e. Body b and later world.addBody(b).(1) and (2) mean that you can't have a Body without a World, which I probably won't need, but it might be nice to have that option [so that I can use it as a template for other objects and such]. Not sure what other pros and cons there are. (3) seems nicer, but it's a lot more work to implement, and it means I have to duplicate most of the data that's already contained in b2Body.
What are your thoughts? I'll CW this just so no one frets.
I still can't lay this to rest. This is what each of the options would look like:
Option 1: (what I prefer)
World w;
Body b;
Fixture f;
b.addFixture(f);
w.addBody(b);
Option 2: (somewhere in the middle)
World w;
Body b(w);
Fixture f(b);
Option 3: (how Box2D does it)
World *w = new World;
Body *b = w->CreateBody(args);
Fixture *f = b->CreateFixture(args);
Options 2 and 3 aren't so different, but it changes who has control over is creating the objects.
How would I actually implement option 3 though? World::CreateBody() has to call b2World::CreateBody(args) which calls b2Body::b2Body() and returns b2Body but never calls Body::Body(args) which is a problem. The b2Body would get fully initialized, but my wrapper has no place to do it's thing... More specifically, how would I write World::CreateBody(const BodyDef &bd)? Assuming BodyDef inherited from b2BodyDef, Body from b2Body, World from b2World, etc.
I think, if you're going to use a third-party library, you should only fight its design if you have a much better reason than oh, I don't like that design pattern much. Your library has a way of doing things — apparently, by using a factory object — and fighting that will increase your code complexity, possibly substantially.
Sounds like the b2World object is a factory for b2Body, so the author has decided that a b2Body has no meaning without its world.
My first reaction would be that this is the interface, so live with it. Have your World object be a factory for your Body. So that's close to approach (1) except that you don't have a public constructor, the World object has a makeBody() method.
You think that Bodies without World make sense? If so, perhaps what you find is that some subset of Body methods could be useful without a World, I'm not clear how you implement them - they clearly can't be implemented by b2Body, because he can't exist without a b2World. So one possibility is that you have a set of config information
class Body {
int howBig;
String name;
Flavour flavour;
// and getter/setters
}
Now these (or at east the bgetters) clearly could make sense with or without World.
With that in mind, I think you may find that you actualy have two "states" of Body, one when it's not associated with World, one when it is. And the actual capabilities are different. Hence you actually have two interfaces.
So have a IndependentBody class and a Body class. The World factory method might have a signature
World {
Body makeBody(IndependentBody);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With