Well I'm coming late to this party, but I can't resist putting my two cents in.
Why is combining getters, setters and private access modifier not enough?
Not enough for what? If combining getters, setters and private access modifiers was a completely bad idea it would have died already. It's still around. It just doesn't do what people were told it does. It does something else.
This exposes implementation. Indeed, it would expose implementation even if the variables were private and we were using single variable getters and setters.
Uncle Bob is taking a shot at the myth that getters and setters provide encapsulation. They don't. They never did. We were told they did. We were lied to. We were fooled because we actually got something good outta the deal. It just wasn't encapsulation.
So what did we get?
We got Aspect Oriented Programming.
Before the languages, plugins, and frameworks provided for Aspect Oriented Programming, before that paradigm existed, getters and setters provided a very important thing to the world of programming. They provided a place to put a break point.
Yes, getters and setters are really debugging code. Sure you can tack on some validation magic but their biggest impact was to help with debugging. Leaving debugging code lying around is a sin though, so we kept this a dark secret.
Unfortunately, the secret corrupted our understanding of a very important concept. Encapsulation isn't simply preventing direct access. It's preserving the right to not know.
The moment you name a function
getX() you've exposed the idea of X. You promised to go get an X. How you implement
getX() doesn't really matter. That isn't the problem. The problem is right there in the name.
What business does any other object have even knowing about the idea of an X?
A pure Behavior Object takes an idea and hides it so nothing else has to think about it. If you have an issue with X this Behavior Object should be the only place you have to look to fix that issue. If you let any ol` thing ask about X you're going to have a lot of places to look to fix that X issue.
Does this mean getters and setters are evil and wrong and should never be used again?
No. It means you should learn there is more in this world of programming than pure Behavior Objects. There are also Value Objects, Data Transfer Objects, Abstract Data Types, and Collections. Not to mention strings and int's. Call them what you like but don't get these mixed up with Behavior Objects. They follow different rules.
Behavior Objects do something none of these others do. They move you from one level of abstraction to another. If I can set X and then get X I haven't changed the level of abstraction at all.
If I can say
Point(x, y).draw() I've moved to another level of abstraction.
If I have to say
draw(p.getX(), p.getY()) then the point didn't change the level of abstraction at all from when it was given x and y. It's just a data dumping ground and it's making drawing something else's problem.
Behavior objects shouldn't be asked questions about their state. They should be told what do to. This principle is called Tell, don't ask.
So why shouldn't everything be a Behavior Object? Well believe me people have tried. But collections are just so darn useful. Sometimes you have work to do that DOESN'T move from one level of abstraction to another. Sometimes you just need to sort something.
I'll leave you with this:
Setters make you mutable. They also let old frameworks initialize objects in stages. Which means you can exist when you're not done being initialized.
Getters turn a behavior object inside out. If idea X has a getter than it's anyone's guess where your X related bug is hiding.
What they are good for is improving dumb data objects that otherwise would just have public state. If you can get away from using those, more power to you. But if you're going to use them then getters and setters will at least let me set breakpoints.
The very idea of getters and setters them came from the Java Bean. It was a specific idea that solved a specific problem that led many designers to use it in ways that remind me of a monkey driving a nail with a lug wrench. It can work but it's painful to watch.
This means I must burn my school copybooks.
If you're studying a subject where the ideas in the books will always be as true today as the day it was written you aren't studying science. You're studying religion.
Don't burn your old books. Keep them around for their historical perspective. They all tell you the date they were published. They'll come in handy when you realize the code you're reading was written before you were born.