Conventions are great when you can speed up your coding and automatically provide self-documenting and standard solutions and that’s probably one of the main reasons why the Convention over configuration pattern got so popular and extended. And that’s fine, unless you abuse or misuse them, as usual, breaking user (or reader) expectations and therefore increasing confusion and time consuming (that is, breaking the Principle of least Astonishment, PLA, even in your contracts and interfaces). And often getter and setter methods are part of this overuse of conventions.
The so popular Java Beans convention is really powerful when providing compatibility for frameworks and libraries which rely on the matching between getters/setters and internal properties of a POJO. The side-effects of developers getting used to code Java Beans though is to see getters and setters everywhere! But do we really need so many getters and setters?
Consider data encapsulation
Setters and getters prevent access to internal class members and hence improve encapsulation, that is, we can define set methods to modify internal state and get methods to access it, filtering interactions via a public interface and therefore having entry points for input validation and state consistency. But to reenforce this principle, we should always limit the access to the least necessary: do other component really need a certain get method? Was a given get method created only for testing purposes? Is it reasonable to actually change the internal state via a set method after object creation? These are common alerts which can spot an abuse and probably be corrected. For instance, consider not exposing set methods for results objects created as output of a calculation, indeed it would probably be a POJO providing several information to the caller, but in this case we would only need to expose getters and not setters: a possible solution would be to expose an interface with only getters while its concrete implementation would also provide setters and not be visible by the caller (for instance, package visibility); otherwise, consider not having any setter method at all and initiate the object only via its (non public?) constructor(s) or through a Builder pattern.
Yet, an overdose of getters and setters may spot a wrong Object Oriented design, when components are forced to get and set values and hence strongly coupled together, pulling data in and out of objects while they should be manipulated inside them (remember the Single Responsibility Principle, SRP, and the Tell Don’t Ask, TDA). The result would probably be an anemic class, not providing any behavior and hence moving related behaviors to other components. Remember: classes are not just structures of procedural programming languages, they should actually provide behaviors as well, hence if the caller would need several get methods consider providing a more concise and useful operation instead.
Consider caller expectations
API users should not need documentation for each and every call (and especially for getters and setters indeed), they should also rely on some conventions. Therefore, they would expect a getSomething to be an accessor method and you would definitely break that expectation if the concerned get method would perform a long processing, I/O interactions or anything more expensive than a single field access (we should however exclude some validation or firing events in case of setters). If your get or set method introduces overhead, if it’s not an atomic operation and requires additional calculation, then consider renaming it. The method length could also be used as a metric: the longer it is the more chances there are to go for a different method name.
Consider other naming conventions
Get and set are verbs and they are great for conciseness and adaptation, hence eligible for many purposes and method names. However, many other options exist which will certainly avoid the ambiguity of invoking an accessor method instead of a more complex one. Yet, often developers don’t like to waste too much time on inventing methods names and fall on the easy option: the universal get. But, did they really need a get or something more meaningful like process, fetch, find, retrieve, compute, determine?
Moreover, when signatures are broken you probably didn’t need a get or a set method: think about setters with more than one parameter and/or returning type or getters with parameters, they may spot a design to reconsider further (did you need to set several properties at once? Shouldn’t they be just part of the constructor? Is that method just a setter or is it doing something more?); when one of the two is missing: consider from the Java standard library String#length or List#size or Enum#name, Iterator#next, Interger#intValue and so on, they are not get methods yet they are short and intuitive. Another example could concern the definition of a fluent interface, for instance applying a Builder pattern, better to have something like withX instead of setX: it would actually be more fluent (i.e. Builder.newObject().withX(x).withY(y), or as real example the Java Scanner and its useDelimiter(x).useLocal(y).useRadix(z) and so on). Finally, try to be consistent among your API, embracing a certain convention over another and thus not introducing astonishment and confusion.
The getters and setters mania can thus be extended even out of Java Beans context, that is, even for POJOs or classes which would never be used by any Java Beans framework or library and let’s state it clearly: it’s not wrong to use get/set methods in these cases, as long as it doesn’t break standard practices and your (technical) common sense. Yet, if concerned classes may be used later on by Java Reflection processing or reflection based framework, then it would still be recommended to keep the get/set convention (think about accessing properties in JSP pages or any other template oriented system using common x.y access pattern, it would rely on naming convention and existences of certain methods indeed). However, there are plenty of cases in which better options would be available and worth to consider.
|Reference:||Getters and setters gone wrong from our JCG partner Antonio Di Matteo at the Refactoring Ideas blog.|