Should the data inserted into a method be as primitive as possible?

Viewed 105

As a general rule, should the parameter be as primitive as possible? And thus have the conversions to whatever data format/class we need be done inside the method?

eg. insert a String and then have the conversion to LocalDate be done inside the - in this case, setter - method?

// inside a class that has a date field 
private LocalDate date;

public void setDate(String stringDate) {
        LocalDate date = LocalDate.parse(stringDate);
        this.date = date;
}

or have this conversion be done outside of the class?

// inside a class that has a date field
...
private LocalDate date

public void setDate(LocalDate date) {
    this.date = date;
}
...

// in TextUI class
...
String stringDate = scanner.nextLine();
LocalDate date = LocalDate.parse(stringDate);
*object*.setDate(date);
...

I am not seeking for an answer to this particular situation, but rather for a general rule. (Thus also not necessarily for setters methods only, but for any method)

On the one hand, to obtain max abstraction, I think the second example is the way to go. On the other hand though, the first example feels more as though the object takes care of its own data integrity.

3 Answers

One relevant rule that is very commonly applies is that every "item" in your code (method, class, package, ...) should have one clearly-defined responsibility.

For example a setter has the task of "changing the state of an object with the caller-provided data".

If you add the code to convert from one data type to another (parsing/formatting) to that method then that method now has 2 separate and independent tasks.

Generally speaking you want to have some area in your code that's responsible to do the parsing/formatting and leave other areas of your code to deal with their own responsibilities.

Disclaimer: this question is dangerously close to opinion-based, but I think the rules discussed here are general enough to just barely miss the close-reason threshold. Others might disagree.

There is no simple, single rule that tells you what to do, albeit the other answer makes a great point: the purpose of a setter should be to set a value, not to parse/validate it. But of course, by renaming it to updateDateFrom() you can already express that you intend to do more than setting a value.

Beyond that, there are really two different views:

  • When you think in "Object oriented" terms and paradigms, then you typically want to use specific types. Types are meant to provide meaningful abstractions, and a Date carries much more semantics than a raw string that happens to contain a date (in some format, or not, because malformed!)
  • But when you come from a functional point of view, many people argue that you pass around "raw" data (without sophisticated types), but that you make sure that the functions operating on that data are used consistently.

From that point of view, my personal stance is to follow the OO approach: and that means that I prefer to use specific types "as early" and as consistent as possible. Passing around strings always carries the risk of late runtime surprises (malformed, invalid timezone, impossible date, you name it). Whereas a Date object can only be null, otherwise you got some real meaningful Date at your disposal. So: much less worrying.

  • Basically the setter method just set the value into the corresponding properties based on the data type of its parameter. There is nothing like parser/converter.
  • In some framework the form field value can be auto converted into specific data type or string using converter by either explicit or implicit.

A very common and general way is to define a static utils method which can convert the date string type into database compatible date format LocalDate whenever required

String stringDate = scanner.nextLine();

public static LocalDate getSQLDate(String stringDate ){
    return LocalDate.parse(stringDate);
}

formBean.setDate(Utils.getSQLDate(stringDate));

 
Related