Consider this case of specialization, where the less specialized class requires access to an object of interface type, but the more specialized class requires access to a concrete implementation of that interface:
class IPropulsionMechanism {
public:
virtual void engage() = 0;
virtual void disengage() = 0;
};
class Engine : public IPropulsionMechanism {
};
class Vehicle {
public:
void travelTo(const Destination& dest) {
mPropulsion.engage();
dest.arrival().wait();
mPropulsion.disengage();
}
void SetPropulsion(IPropulsionMechanism& prop) {
mPropulsion = prop;
}
protected:
IPropulsionMechanism& mPropulsion;
};
class Car : public Vehicle {
void adjustTiming() {
// Propulsion Mechanism MUST be Engine
}
The problem is that Car will need to know the details of it's engine, it cannot operate without it, and yet the SetPropulsion method accepts only the interface type.
Some legacy code before me now deals with this by forcing SetPropulsion to be contravariant (via a dynamic_cast to Engine). Obviously this cast makes SetPropulsion violate the Liskov principle.
My tentative solution is to add an Engine& mEngine member to the subclass, and a SetEngine method:
void SetEngine(Engine& engine) {
mEngine = engine;
Vehicle::SetPropulsion(engine);
}
However my only reservation is that the subclass will have access to two references to essentially the same thing (mPropulsion and mEngine).
Note that there may be many such members in the relationship, a car requires an Engine, CarSeat, AirConVentilation, &c. but a Vehicle must have IPropulsionMechanism, ISeat, and IVentilation, &c.
I suspect there is a pattern that already covers this kind of specialization. Hopefully someone can name it for me.
Aucun commentaire:
Enregistrer un commentaire