According to Is "avoid the yo-yo problem" a valid reason to allow the "primitive obsession"?, I should define "price" like this:
public class Main{
private Price price;
}
public class Price{
private double priceValue;
public static void roundToValidValue(double priceValue){
}
}
instead of
public class Main{
private double price;
}
public class PriceHelper{
public static double roundToValidValue(double priceValue){
}
}
because I should encapsulate the logic about Price into a class to increase maintainability. However, I found it seems go against the goal of "use most abstract type as possible" (Why define a Java object using interface (e.g. Map) rather than implementation (HashMap)) :
As I understand, one of the goal of "use most abstract type as possible" is to reduce the coupling between classes, which lets the clients avoid using methods that they don't call, and hence the clients wouldn't depend on the methods that they don't use. However, back to the Price class, I found that some clients don't call "roundToValidValue" at all. If I follow the "avoid primitive obsession" rule and encapsulate "roundToValidValue" into a new class, the clients that don't call "roundToValidValue" at all would also depend on "roundToValidValue", which seems go against the goal of "decoupling" that suggested by "use most abstract type as possible".
Also, according to Should we define types for everything?, I should avoid using primitive types to represent business model directly, ie: I should change
public class Car{
private double price;
private double weight;
public void methodForPrice(double price){
}
}
into
public class Class{
private Price price;
private Weight weight;
public void methodForPrice(Price price){
}
}
which can avoid the situation that calls the wrong method ,ie :methodForPrice(weight). However, according to Why define a Java object using interface (e.g. Map) rather than implementation (HashMap), it suggests using most abstract type as possible, ie:
public LinkedHashMap<String,Stock> availableStocks;
public HashMap<String,Stock> unusedStocks;
public class Main{
public void removeUnusedStocks(Map<String,Stock> unusedStocks){
}
}
which I found it may suffer from the problem of "primitive obsession" : I may call "removeUnusedStocks(availableStocks)" wrongly. So I think use more specific type:
public class Main{
public void removeUnusedStocks(LinkedHashMap<String,Stock> unusedStocks){
}
}
is better even if both versions works idendically and hence I think "use most abstract type as possible" go against the goal of "avoid primitive obsession".
As the result, I think the goal of "avoid primitive obsession" and "use most abstract type as possible" go against each other and hence "avoid primitive obsession" and "use most abstract type as possible" contradicts each other, is that true?