For example suppose I have a class Vehicle and I wish for a subclass ConvertibleVehicle which has extra methods such as foldRoof(), turboMode(), foldFrontSeats() etc. I wish to instantiate as follows
Vehicle convertible = new ConvertibleVehicle()
so I still have access to common method such as openDoor(), startEngine() etc. How do I designed such a solution?
To clarify my two initial solutions, neither of which I am happy with are:
- Have dummy methods foldRoof(), turboMode(), foldFrontSeats() which I override in ConvertibleVehicle only, leaving them to do nothing in other subclasses
- Have abstract methods foldRoof(), turboMode(), foldFrontSeats() and force each subclass to provide an implementation even if it will be blank in all instances other than ConvertibleVehicle
The above seem slightly convoluted since they both pollute the base class as I add an increasing number of subclasses each with their own unique functions
After reading some of the responses perhaps there is some type of fundamental flaw in my design. Suppose I have a class VehicleFleet which takes vehicles and instructs them to drive as follows:
public VehicleFleet(Vehicle[] myVehicles) { for (int i=0; i < myVehicles.length; i++) { myVehicles[i].drive(); } }
Suppose this works for dozens of subclasses of Vehicle but for ConvertibleVehicle I also want to fold the roof before driving. To do so I subclass VehicleFleet as follows:
public ConvertibleVehicleFleet(Vehicle[] myVehicles) { for (int i=0; i < myVehicles.length; i++) { myVehicles[i].foldRoof(); myVehicles[i].drive(); } }
This leaves me with a messy function foldRoof() stuck in the base class where it doesn’t really belong which is overridden only in the case of ConvertibleVehicle and does nothing in all the other cases. The solution works but seems very inelegant. Does this problem lend itself to a better architecture?
I’m using Java although I would hope that a general solution could be found that will work in any object oriented language and that I will not need to rely upon language specific quirks
I’ve done this in similar situations.
Option A)
If the specialized operations are part of the same sequence as a base operation ( e.g. ConvertibleVehicle needs to be foldRoof before it can drive ) then just put the specialized operation inside the base operation.
So the effect of driving a fleet will be some of them will fold their roof before being driven.
The specialized method is not exposed in the object public interface but is called when needed.
Option B)
If the specialized operation are not part of the same sequence and must be called under certain ‘special’ circumstances then let a specialized version of a client call those specialized operations. Warning, this is not so pure nor low coupling but when both objects ( the client and the service ) are created by the same ‘condition’ or builder then most of the times is ok.
Almost the same as the previous example, only in this case foldRoof is public also.
The difference is that I need an specialized client:
That instaceof look kind of ugly there, but it may be inlined by modern vm.
The point here is that only the specialized client knows and can invoke the specialized methods. That is, only RoofAwareFleetHandler can invoke foldRoof() on ** ConvertibleVehicle**
The final code doesn’t change …
Of course, I always make sure the fleethandler and the array of Vehicles are compatible ( probably using abstrac factory or builder )
I hope this helps.