Is it a good practice to make some data processing/validation in getters and setters? In wikipedia here there are 2 examples:
Are these good examples or it is better to avoid it? If it is better to avoid it, how can I implement these 2 examples above in a better way?
UPDATE: Please, Do not take examples with date and etc serious. It is just an example, of course it can be stupid.
Real example which I had.
I have an external third party system and I have to make integration. This external system expect from me some data as class with getters and setters. I have to pass 2 fields there, id (something like 09df723987cd7 (let's say GUID)) and formattedID something like "objecttype/09df723987cd7". I cannot change this external system.
I want to implement it like
getId() {
return id
}
getFormattedId() {
return objectType + "/" + id;
}
objectType is another field in this class.
My Question: is it OK, or there is some more elegant way to implement it?
The examples you provided are not good fit, at least not in the form and with the names you mentioned.
I'll try with some better examples:
Setters
You might want to use them for validation mostly. As an example setDate(Date d)
could check the data is in a certain range, e.g. not more than 20 years into the future etc. (depends on your requirements).
Getters
If those contain more than simple logic they probably represent virtual properties, i.e. properties that don't have an underlying field but are calculated on the fly.
Let's take getAmount()
for example: there might not be any field amount
or the amount might be stored in cents (or smaller) for some reason (e.g. no precision issues). Thus getAmount()
might look like this:
public double getAmount() {
return amountInCents / 100.0;
}
Note that the name getAmount()
might be misleading though, so you might be better off using a name like getAmountInUSD()
or similar.
General
Using getters and setters in Java is adviceable in most cases since you'd be able to the following (list not complete):
Anecdotes with setters and getters
My point? Like anything in this world, it's not a black-and-white clear cut what is the best way to use getters and setters.
Setterless classes and Builder pattern
Sometimes a class has heaps of properties (impractical to design a constructor taking all of them, and then if you do it anyway it is excruciating painful to use). Supplementary, many times such classes should be immutable after construction (so no public setters).
A Builder pattern with a Fluent interface gets the things... well... flowing
To validate or not to validate at setting time ?
For most of the cases, it is Ok to perform a validation at the setters level. However, it is not always wise to do it.
For example, there are cases in which the object can "transition" through invalid states and reach a "valid and self consistent state" only after a sequence of calls in the setters.
For example: "A motorcycle without two wheels is not a valid motorcycle" doesn't mean that I cannot setFrontWheel(null)
as a temporary stage in repairing my motorcycle... design by contract be damn'd, I'll just call validateMe
at the end and be done with it.
Multi-setters
If you need to perform validation on setting and certain combination of values don't make sense, use a multi-setter:
void setDate(int y, int m, int day) {
int maxDaysInMonth=0;
switch(m) {
case 1:
case 3:
...
case 11:
maxDaysInMonth=31;
break;
case 2: // that's feb
maxDaysInMonth=isLeap(y) ? 29 : 28;
break;
case 4:
case 6:
...
maxDaysInMonth=30;
break;
default: // only 12 months in the year
throw something;
}
if(d>=maxDaysInMonth) {
// you catch my drift, yeah?
}
}
Getters:
"computed getters" - like that "100 USD" - is not a property in itself, many would argue the method should be called "computeSomething" or "toSomeForm" (like "toString"), but... is just so convenient and easy to remember Rectangle.getCentreX
"restricted getters" - like
protected ArrayList listeners; // look-but-don't-touch getter public List getListeners() { return Collections.unmodifiableList(this.listeners): }
class Rectangle { void getCentre(Point2D resultHere) { resultHere.set(minX+width/2, minY+height/2); } // and not // Point2D getCentre() { // return new Point2D.Double(minX+width/2, minY+height/2); // } // because... performance. }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With