I have several classes that all inherit from a generic base class. The base clas
ID: 643078 • Letter: I
Question
I have several classes that all inherit from a generic base class. The base class contains a collection of several objects of type T.
Each child class needs to be able to calculate interpolated values from the collection of objects, but since the child classes use different types, the calculation varies a tiny bit from class to class.
So far I have copy/pasted my code from class to class and made minor modifications to each. But now I am trying to remove the duplicated code and replace it with one generic interpolation method in my base class. However that is proving to be very difficult, and all the solutions I have thought of seem way too complex.
I am starting to think the DRY principle does not apply as much in this kind of situation, but that sounds like blasphemy. How much complexity is too much when trying to remove code duplication?
EDIT:
The best solution I can come up with goes something like this:
Base Class:
protected T GetInterpolated(int frame)
{
var index = SortedFrames.BinarySearch(frame);
if (index >= 0)
return Data[index];
index = ~index;
if (index == 0)
return Data[index];
if (index >= Data.Count)
return Data[Data.Count - 1];
return GetInterpolatedItem(frame, Data[index - 1], Data[index]);
}
protected abstract T GetInterpolatedItem(int frame, T lower, T upper);
Child class A:
public IGpsCoordinate GetInterpolatedCoord(int frame)
{
ReadData();
return GetInterpolated(frame);
}
protected override IGpsCoordinate GetInterpolatedItem(int frame, IGpsCoordinate lower, IGpsCoordinate upper)
{
double ratio = GetInterpolationRatio(frame, lower.Frame, upper.Frame);
var x = GetInterpolatedValue(lower.X, upper.X, ratio);
var y = GetInterpolatedValue(lower.Y, upper.Y, ratio);
var z = GetInterpolatedValue(lower.Z, upper.Z, ratio);
return new GpsCoordinate(frame, x, y, z);
}
Child class B:
public double GetMph(int frame)
{
ReadData();
return GetInterpolated(frame).MilesPerHour;
}
protected override ISpeed GetInterpolatedItem(int frame, ISpeed lower, ISpeed upper)
{
var ratio = GetInterpolationRatio(frame, lower.Frame, upper.Frame);
var mph = GetInterpolatedValue(lower.MilesPerHour, upper.MilesPerHour, ratio);
return new Speed(frame, mph);
}
Explanation / Answer
In a way, you answered your own question with that remark in the last paragraph:
I am starting to think the DRY principle does not apply as much in this kind of situation, but that sounds like blasphemy.
Whenever you find some practice not really practical for solving your problem, don't try to use that practice religiously (word blasphemy is kind of a warning for this). Most practices have their whens and whys and even if they cover 99% of all the possible cases, there's still that 1% where you may need a different approach.
Specifically, with regard to DRY , I also found that sometimes it is actually better to even have several pieces of duplicated but simple code than one giant monstrosity that makes you feel sick when you look at it.
That being said, existence of these edge cases should not be used as an excuse for sloppy copy&paste coding or complete lack of reusable modules. Simply, if you have no idea how to write a both generic and readable code for some problem in some language, then it's probably less bad to have some redundancy. Think of whoever has to maintain code. Would they more easily live with redundancy or obfuscation?
A more specific advice about your particular example. You said that these calculations were similar yet slightly different. You might want to try breaking up your calculation formula to smaller subformulas and then have all your slightly different calculations call these helper functions to do the sub calculations. You'd avoid the situation where every calculation depends on some over-generalized code and you'd still have some level of reuse.