5

I have a question about best design practices. I have been attempting to build more immutable components into my project because I read they were easier to maintain in the long run and wanted to test this.

When you have a class with immutable data members, say

 public/private final int importantNumber = 3;

Should the int still be declared as private and given an accessor method, or because its finals, what is the hard in allowing direct access and making it public? I don't see any issues with it being made public because you are unable to change it.

In my case, the immutable object is created with values that are passed into it and then will self populate the others from a database, with everything being final.

Or is this merely a question of preference and will spark a religious war? As there are lots of questions about accessing the data member from inside the class, I want to make it clear that I am asking from another external class attempting to get the value.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
Fering
  • 322
  • 2
  • 18
  • an accessor method has the possibility to contain more logic (calculations and so on), whereas the field does not, using a method also allows you to rename the field (as it is only used internally) – Lino Jan 30 '19 at 14:45
  • 1
    See https://stackoverflow.com/questions/1568091/why-use-getters-and-setters-accessors – Bentaye Jan 30 '19 at 14:46
  • I would always use a getter, because it allows easy mocking in unit tests. – NeplatnyUdaj Jan 30 '19 at 14:51
  • @NeplatnyUdaj But that could be "package protected" . If it is public, you have no control who else will be calling it, at least before Java 9 and modules. – GhostCat Jan 30 '19 at 14:53
  • What I meant is that with a testing framework like mockito, I don't have to create a real instance(which might be cumbersome) when I need to mock just a single value. – NeplatnyUdaj Jan 30 '19 at 15:04
  • 1
    @GhostCat Your point was dead on, I only thought about the here and me, I had not considered who might be using the code later on. The goal is for easy maintenance, so while I cringe about getters that return a value and do nothing else, they do have their place. Its too bad there isn't a keyword that I can include which lets me declare a psudo-scope and name for a getter. private int importantNumber(public getImportantNumber) = 3; Then if needed I can just define the getter later. – Fering Jan 30 '19 at 15:11
  • I think other languages go into that direction, but alas, this is Java, boilerplate is thy name. – GhostCat Jan 30 '19 at 15:13

3 Answers3

5

Making things public allows other code to rely on it.

It doesn't matter if the data is mutable or immutable. As soon as some other code makes itself dependant on that information, you enable future problems. And in any larger project, these problems will manifest themselves sooner or later.

Making things public, all of a sudden, (internal) implementation details can leak into other code! And of course: if that data is mutable, that just opens a real can of worms.

But even a simple if (someObject.someField == whatever) then do this else do that can quickly turn into a huge problem. Just assume you have that code in 10, 50, 100 different places in your huge project.

Thus, your default rule is: hide your information. Making things public is the exception, it happens because you absolutely want your design to be that way. Your default is to give your fields (and even methods) the most restrictive visibility that still allows you to implement your requirements.

And note: it is just "slightly" better to hide the field and having an accessor method for it. Because if (someObject.someMethod() == ...) leads to the same problems. And (almost) worse: now you decide that someMethod() should do something different, to solve one specific problem. But are you sure that the other 99 usages of that method call work fine with that change?!

Final caveat: Java 9 introduced the module concept, so you are now finally able to have something public, but still not usable from outside your module. But that is more of a theoretical addendum, I would still go with the base rule and make not things public unless I have good reasons to do so. If you want to access that information, say for unit tests, then a package protected getter should do.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 1
    Your first line actually said it all. I didn't think of that. So wish I had a proper data structure from C++. Classes are supposed to be living things but sometimes I just need something to hold data. – Fering Jan 30 '19 at 15:06
  • @Fering For "true" data classes, things are slightly different. If it is "just" a "record" (or bean in java speak), a plain class with public fields *might* be acceptable. Until you come in 2 years later, and find that you need something else, and start reworking all the direct accesses. Been there, done that. – GhostCat Jan 30 '19 at 15:15
  • 1
    Which is why after I read your comment I went back, changed publics to privates, and added accessors, and now reworking the code. Not making a bean however. – Fering Jan 30 '19 at 15:18
1

There is no practical difference between having a final field declared public or having it private with a public getter.

There are a lot of theoretical handwavy arguments why it's really bad to have public fields, but there actually is no real practical reason not to do it. Yes, in theory you could change the getter later to do something different, but you probably won't. Even if you want to most people will tell you a getter should really just return the field it gets without additional logic.

Just to be more clear, both options are equally wrong. Fields shouldn't be public, and there shouldn't be a getter either. But, if you do one of those, the other is equally wrong. Hope that helps :)

Robert Bräutigam
  • 7,514
  • 1
  • 20
  • 38
  • There is one: you can always come in 3 years later and change that method body to `throw new RuntimeException("you shouldnt have called this method, the javadoc told you so, burn mf burn");` ... of course, we would never do that, would we. – GhostCat Jan 30 '19 at 14:57
  • @GhostCat Hehe :) Don't look at me, it wasn't me :) – Robert Bräutigam Jan 30 '19 at 15:01
  • @Robert Yeah, one of the articles I read also mentioned that getters and setters were evil and should be avoided. I just cant prevent myself from using them in all cases. – Fering Jan 30 '19 at 15:04
  • I remember when I first learned about Bertrand Meyer and the https://martinfowler.com/bliki/UniformAccessPrinciple.html ... and I thought: oh, thats so reasonable to **not** distinguish between x.foo and x.foo() ... but well, 25 years later, maybe I am getting too old for such things. – GhostCat Jan 30 '19 at 15:08
  • @Fering There is very little *practical* articles out there how to *avoid* setters/getters and data-objects in general. Object-orientation is not just the language, it has deeper implications. You have to think along business behavior to avoid needing data all the time. I have a couple of (hopefully) practical articles on the subject here: https://javadevguy.wordpress.com/ – Robert Bräutigam Jan 30 '19 at 15:10
  • @RobertBräutigam I'll take a look at some of the articles when I have time, thank you for sharing. I know there is a lot more to OO than what I do, but I try to be better than I am. I admit when I have been wrong and strive to correct it. – Fering Jan 30 '19 at 15:15
  • @Fering I found an article of mine from a while ago that describes a real-world exchange to not implement a getter, if you need examples: https://javadevguy.wordpress.com/2017/03/26/object-oriented-solutions-avoiding-getters/ – Robert Bräutigam Jan 30 '19 at 15:15
  • 1
    *"There is no practical difference between having a final field declared public or having it private with a public getter."* ... aside from the fact that making an immutable field public ties the API to the implementation. Once distributed, your class must forever support that field, even if later on some other implementation would be preferred. There are situations in which making fields public is the right thing to do (eg. making the constants in an enum class public), but it is always true that making them public discourages loose coupling. – scottb Jan 30 '19 at 15:17
  • @scottb I agree with you and said so in my reply. My point is, that making it private and then having a public getter does not solve any of the problems you listed. Therefore the two are equally bad. – Robert Bräutigam Jan 30 '19 at 15:21
0

When you declare an object final that be immutable and no one can change the value of that.

But define public or private an object important according to encapsulation principle in OOP, that you must declare a method for getting that field till in later you can track easily to where this object need and which class needs this value.

SamiAzar
  • 1,260
  • 13
  • 29
  • 1
    Your reasoning is wrong. My IDE can tell me exactly what usages for x.someField are out there, or for x.someMethod(). The only difference is this: when you expose a method, you can change the behavior of that method without the caller noticing. Which can lead to a whole other set of problems. *Changing* code later on is something you try to avoid .... – GhostCat Jan 30 '19 at 14:48