Yes, if your class has a million getters and setters it's probably doing far too much for its own good. I like the template idea, it reduces boilerplate code while preserving encapsulation. On the other hand, making the member public is not a good idea unless it's a trivial member or a trivial class, because as soon as you need to enforce a condition on this member your class interface has to change, and all code depending on the class breaks (sure, the fix is a find/replace away, but then you need to recompile etc..)
I kind of liked the Object Pascal/Delphi way for properties (sorry if there are any syntax errors, it's been months since I wrote any):
interface ... private fFoo: Integer; fBar: String; public property Foo: Integer read fFoo; // read-only, default getter (no boilerplate getter method) property Bar: String read getBar write setBar; // read-write, custom getter/setters ... implementation function getBar: String; begin if (fBar <> "sentinel") then Result := fBar; end; procedure setBar(Value: String); begin if (Value <> "sentinel") then fBar := Value; end;
Which I think is advantageous in that you immediately see from the interface what is read-only and what is read-write (or write-only, should you have a use case for that) and you can easily switch from a default getter (or setter) without even changing the class interface. As far as client code goes, it just thinks Foo and Bar are properties as if they were ordinary members (accessed by class.Foo) and any reads go through the getter, any writes go through the setter. It also works with indexed properties. I think it's rather neat, I'm sure it has its downsides though.
Of course, if you are absolutely certain that any value of the member is valid and you don't need to do anything when it changes, and that you will never reconsider this design decision, just make it public. This is rather rare, though, usually this kind of member is set inside a constructor or other initialization method via some argument.