I have a car maintenance garage program that has an abstract Vehicle
class that has several derived classes like Car
MotorCycle
, etc. Each of those derived vehicles in turn is either a fuel or an electric vehicle. So instead of having a FuelCar
, ElectricCar
, FuelMotorCycle
, ElectricMotorCycle
etc, I'm trying to implement it using composition.
The problem now is that I would have to check all the time if it's an electric or fuel vehicle, and then do as cast
(that's like reinterpret_cast from c++) accordingly, or would have to wrap each as cast
with try catch
. It adds complexity to the code.
Another option was removing the EnergySource
empty class and have each vehicle to hold both Fuel
and Electric
and to initialize only one in the ctor, but it doesn't seem right to have a fuel car that also have an electric part (even if that part is null). Although this seems the simplest of the three.
Any suggestions on what is the best approach?
Here's the UML diagram of what I currently have:
Best Answer
My sympathies.
Ok. Then you'd better not have both a
Fuel
andElectric
properties inVehicle
. It "sends the wrong message."Throughout the StackExchange universe I see the way over-use of
interface
s (the keyword kind). I think it is an exuberant mis-application and mis-understanding of "code to interfaces not implementation."Jessica Simpson on UML
Yes.
Wrap a
Vehicle
in aVehicleEnergy
classGiven the design as shown, pass a
Vehicle
instance into aVehicleEnergy
class with appropriate wrapper methods, or properties, to query the vehicle-EnergySource kind that it is. But I don't see how you can get around the fact that somewhere, somehow you have to interrogate the object.This feels like a good separation of concerns compromise. I wonder if the flurry of comments on this thread is the result of - a symptom of - conflicting concerns.
I think this hybrid design (pun intended) expresses the separate aspects and then expresses their interaction in a coherent interface (the non-keyword kind).
The
Vehicle
object can always be used as-is, or disguise itself, so to speak.Oh, yes... I might use the factory pattern and pass in an
enum
for the vehicle-enery desired. There will be no enum member for a hybrid vehicle so this becomes a strongly typed way of communicating that "hybrid" is undefined.