Getters and setters are evil. No need to argue about this, it's settled. You disagree? Let's discuss that later. For now, let's say, we want to get rid of getters. The key question is how is it possible at all? We do need to get the data out of an object, right? Nope. Wrong.
I'm suggesting to use "printers" instead. Instead of exposing data via getters, an object will have a functionality of printing itself to some media.
Let's say this is our class:
We need it to be transferred into XML format. A more or less traditional way to do it is via getters and JAXB:
This is a very offensive way of treating the object. We're basically exposing everything that's inside to the public. It was a nice little self-sufficient solid object and we turned it into a bag of data, which anyone can access in many possible ways. We can access it for reading, of course.
It is convenient to have these getters, you may say. We are all used to them. If we want to convert it into JSON, they will be very helpful. If we want to use this poor object as a data object in JSP, getters will help us. There are many examples in Java, where getters are being actively used.
This is not because they are so effective. This is because we're so procedural in our way of thinking. We don't trust our objects. We only trust the data they store. We don't want this
Book object to generate the XML. We want it to give us the data. We will build the XML. The
Book is too stupid to do that job. We're way smarter!
I'm suggesting to stop thinking this way. Instead, let's try to give this poor
Book a chance, and equip it with a "printer":
This isn't the best implementation, but you got the idea. The object is not exposing its internals any more. We can't get its ISBN and its title. We can only ask it to print itself in XML format.
We can add an additional printer, if another format is required:
Again, not the best implementation, but you see what I'm trying to show. Each time we need a new format, we create a new printer.
You may say that the object will be rather big if there will be many formats. That's true, but a big object is a bad design in the first place. I would say that if there is more than one printer—it's a problem.
So, what to do if we need multiple formats? Use "media", where that printers will be able to print to. Say, we have an object that represents a record in MySQL. We want it to be printable to XML, HTML, JSON, some binary format and God knows what else. We can add that many printers to it, but the object will be big and ugly. To avoid that, introduce a new object, that represents the media where the data will be printed to:
Again, it's a very primitive design of that immutable
Media class, but you got the idea—the
media accepts the data. Now, we want to print our object to JSON (this design is not really perfect, since
JsonObjectBuilder is not immutable, even though it looks like one...):
Now, we make an instance of
JsonMedia and ask our book to print itself there:
Voilà! The JSON object is ready and the book has no idea about what exactly what printed just now. We need to print the book to XML? We create
XmlMedia, which will print the book to XML. The
Book class stays small, while the complexity of "media" objects is unlimited.
My point here is simple—no getters, just printers!