Consider the code snippet
public interface Car
{
string getColor();
void Drive();
}
public class CarWithAutomaticTransition : Car
{
public string getColor() { return "Red"; }
public void Drive()
{
// Drive implementation...
}
}
Now consider a car with a manual transmission.
public interface IShiftable
{
void upShift();
void downShift();
}
public CarWithManualTransmission : Car, IShiftable
{
public string getColor() { return "Green"; }
public void drive()
{
// Drive implementation
}
public void upShift()
{
// upShift concrete implementation...
}
public void downShift()
{
// downShift concrete implementation...
}
}
It sounds stupid, but in efforts to reduce the number of "if's" in code, I've been reading about the null object pattern where (in this example) the IShiftable interface could actually be implemented in the automatic transition, but with no implementation. The alternative is to do a run-time-type-check on the object to see if it implements IShiftable.
The problems (tradeoffs) I see are the NullObject implementation seems to be somewhat misleading in that there's an interface with no implementation. However, you don't have to do run-time type checking and could just call that method if you need to.
The interface-specific implementation seems too specialized in that it's difficult to have one client handle all Car implementations be they manual or automatic transmission.
Is there an option I'm overlooking here, or is it a design problem and if so, an example would be appreciated.
IShiftable
. The difference is that one shifts automatically, while the other does not.shiftUp
method would be largely the same in both an automatic and a manual car, as they both shift gears. It's more thedecideToShiftUp
logic that is different. This is why I mention that it's about imaginary requirements. You expect something completely different than Robert/me for whatshiftUp
would contain.shiftUp
, or is the act of shifting a gear the same even though the decision at which RPM ro shift is different?