I will explain with an hypothetical example.
Suppose that my domain is Cars. Everyone around the software, talks about cars. Car
is the aggregate root of aggregate roots. For example, CAR
table has 150+ columns in database (irrelevant for this question, but for you to imagine).
So, there is class in the system called Car
. This class has a lot of fields and behavior in it.
Suppose that given a Car
, we have to calculate its HorsePower
. This calculation has its own rules and logic. But for the calculation only a part (some fields) of the Car
is required. And I want to extract this logic from the Car
class in order to make it more visible where this happens, how it happens and what information is needed to happen.
So I end up with something like this, which is pure functional:
public class HorsePowerCalculator{
HorsePower calculate(Car c){..}
}
My doubt is the following. If I pass a Car object to calculate
, I have 2 issues (according to my opinion).
a) What HorsePowerCalculator
needs in order to do its job, its not pretty straight forward. Because I pass the whole Car object, HorsePowerCalculator
can access all (read) properties of a car.
b) For testing HorsePowerCalculator
in the unit test level, I need to create a Car
object which is not a trivial job. Other things must be taken to consideration where they are irrelevant for HorsePowerCalculation.
So, I was thinking that I solve the above mentioned issues by doing this:
public interface HasHorsePower{
int getNumberOfPistons();
EngineType getEngineType();
FuelType getFuelType();
//HorsePower needs also non-cohesive properties.
//This is why I can't group the properties to i.e "Engine" class
int getNumberOfWheels();
}
Then:
public class Car implements HasHorsePower{
}
And finally:
public class HorsePowerCalculator{
HorsePower calculate(HasHorsePower something){..}
}
After this, I gain:
a)it is pretty straight forward what information is needed to calculate horse power. All property/methods of the interface
b)Testing calculations and logic of HorsePowerCalculator
means a TestDouble in the test suite with just setters/getters. Then just assert the calculation results.
My doubts are that the only HasHorsePower
implementation will be...well.. only the Car
Is this solution a code smell, or let's say not optimal? What should I do in this case?