When should I continue to make derived classes, and when should I just add conditionals to my code? eg for a missile
class Object;
class Projectile : public Object;
class Missile : public Projectile;
class MissileGuided : public Missile;
Or should I implement that last one in the missile's code?
void Missile::Update()
{
if(homing && ObjectExists(Target))
TurnTowards(Target.Pos)
Pos += Motion;
}
I'm thinking that for all the finer details the second one is better, because you start getting combinations of things (eg some missiles may not show on the radar, some may be destroyable, some may acquire new targets if the original is destroyed or out of range, etc)
However then the same could be said for regular projectiles sharing properties of missiles in some cases (eg may be destroyable, large projectiles may show on radar, etc)
And then further I could say that projectiles share properties with ships (both move, on collision they do damage, may show on radar, may be destroyable...)
And then everything ends up back as like 3 classes:
class Entity;
class Object : public Entity;
class Effect : public Entity;
Where is a good point to draw the line between creating derived classes, and implementing the features in the method with flags or something?
There are three major features in object-oriented programming that makes them different than non-OOP languages: encapsulation, inheritance and polymorphism.
Derived classes are used for augmenting the functionality of base class by adding or modifying the properties and methods to suit the requirements of the specialization necessary for derived class.
Object-oriented programming has four basic concepts: encapsulation, abstraction, inheritance and polymorphism.
The main ideas behind Java's Object-Oriented Programming, OOP concepts include abstraction, encapsulation, inheritance and polymorphism.
You may want to consider using strategy pattern instead of both approaches and encapsulate behaviours within external classes. Then the behaviours can be injected into the Missile class to make it GuidedMissile or SpaceRocket or whatever else you need.
This way excessive branching of logic within the Missile class could be avoided and you would not need to go into logical complexities associated with the deep inheritance.
Wikipedia has a collection of samples of the pattern usage in several languages: http://en.wikipedia.org/wiki/Strategy_pattern
interface INavigable {
Course calcCourse (Position current, Destination dest);
}
Class GeoStationaryRocketCPU implements INavigable {
Course calcCourse (Position current, Destination dest) {
return dest.getShortestRouteTo (current).getCourse();
};
}
Class GuidedMissileCPU implements INavigable {
Course calcCourse (Position current, Destination dest) {
return dest.getLowestAltRouteTo (current).getCourse();
};
}
class Missile {
INavigable CPU;
void setCPU (INavigable CPU) {
this.CPU = CPU;
}
void fly ()
{
...
course = this.CPU.calcCourse (pos, dest);
...
}
}
As suggested by another collegue, you could consider using Decorator pattern as well. Just to highlight couple of design issues that might be important in your context if you were to take that route:
Nonetheless, when provided with a ready-made immutable implementation of Missile decoration could be the key to "unlocking" it and implementing the strategy pattern, to provide the Missile with all sorts of required behaviours.
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