I'm writing a class Tracker
that will expose to the client methods to get the current status of user's training, like distance, pace, calories, etc. Imagine this values as getters.
class Tracker{
float getDistance();
float getTime();
float getCalories();
}
Now, thinking ahead, I may discover a way to also get the elevation, and then maybe (not at the same time) the number of steps, so my problem is how to better solve this design.
First thought, classic inheritance
My first thought was to just subclass this interface, so I'll end up with
class ElevationTracker extends BaseTracker{
float getElevation();
}
But then, I may want to add a StepTracker
, extending the ElevationTracker
so I have both stats.
class StepTracker extends ElevationTracker{
float getStepsCount();
}
This looks a bit weird to me, because the StepTracker
now implicitly provides the Elevation stat, and it could have been the other way around, the ElevationTracker
extending StepTracker
, in this case it's just a matter of which feature I discover first.
Also, I'm not completely sure if this inheritance is consistent with the specialization philosophy
A single class for everything
Another idea, maybe the simplest, is to have just one class Tracker
and any time I want to add a new feature, change this class by adding a new method to it to retrieve this feature's information; and then the client can update its code to use this new features. So for example, next month I change the Tracker
class and it looks like this
class Tracker{
float getDistance();
float getTime();
float getCalories();
//This is new
float getElevation();
}
I think this solution like if I had thought of this Elevation feature before (The first time I created Tracker
class), I would have added this last method from the beginning.
I do it now just because now the "requirements have changed"
Making each feature a class
Another thought was to not think every feature as the methods of a class, but as a class on its own, meaning that I would have an interface like Tracker
interface Tracker {
float getValue();
/** Maybe some other methods */
}
and then have a class for each feature
DistanceTracker
TimeTracker
CaloriesTracker
- ...
So then I would just add a new ElevationTracker
and a StepTracker
that are independent from each other.
The problem here is that there are some features that depend on others, like for example PaceTracker
and CaloriesTracker
may depend on DistanceTracker
, so they will probably need receive an instance of DistanceTracker
.
Also, the client code may become a bit messy, having to hold an instance for each feature. And the most important pitfall I see is that I would usually use all this trackers together, I probable won't use just the DistanceTracker
or just the ElevationTracker
, so maybe there's no benefit in having each feature separately
Conclusion
I would like to know which of this options is the best, or if there's another better option. Maybe I can reconsider one of them with some tweaks or adding a design pattern to improve it.
In my opinion, the Single class option provides faster development, considering that, although the others make use of OOP features, they just move the problem of updating a class already written from the Tracker class to another client or intermediate class.
Aucun commentaire:
Enregistrer un commentaire