The concept of "setters" and "getters" is not a new one, but serves a few purposes.
First, as visage explained, setters and getters allow access to protected data, while reducing coupling. What this means exactly is not immediately obvious, but it means that tracking down changes to the data becomes much easier. Lets say that you're running your application and you discover that the value of some public field is being changed to an incorrect value. To determine WHERE it's being changed to an incorrect value you would need to set breakpoints at nearly EVERY place that public variable is set, and step through each to ensure correct functionality. ZOMG!
On the other hand, if you used a setter/getter for the field, then you could simply put a breakpoint within your accessor and POOF! With a single breakpoint you can monitor all changes to the protected data.
Also as visage pointed out, using accessors you can easily rename your variables, or even the data types of your variables without it being exposed to the users of your class. This ability to hide the internal workings of a class from the outside world is called encapsulation, and is key to OOP. A nice side effect of this is that changes to the internal implementation, field names, data types, etc...doesnt require a recompile by every assembly that uses your class. With public fields, a change in name or data type would be a change in the class's interface, and thus, would require a recompile by all clients.
In addition to being able to change the name and data type of the protected data without having to "fix" the changes everywhere, getters/setters also allow you to create data procedurally. For example, lets say you have the following class:
public class Rectangle{ public int Area { get { return m_Height * m_Width; } } protected int m_Height; protected int m_Width; }
In the example above I use a Property (C#'s Getters & Setters) to provide access to the Area data of the class. In this case, however, the area of the rectangle isnt actually stored anywhere, and is instead computed dynamically every time someone requests it.
If I had created a public field called Area, I would have had to make sure that its value was always in sync with the height and width fields. That is, if anyone, anywhere changes EITHER height or width, I would have had to recompute the area field also. That's a lot to keep in sync, even for such a simple example.
And Finally, setters/getters are useful for validation. Lets say that I have a class such as the follows:
class Character{ public float m_Health; // Health is a %, from 0.0 to 1.0}
In the above example, I have a character who's health is a % from 0 to 1. Now, floats, by definition, allow me to use values beyond the range of 0 to 1. If I were to expose the above field as written, every time/place someone were to set the health of my character, I'd also need to call some kind of validation function to make sure the health was set correctly. However, if I use setters/getters (aka Properties) I can do the following
class Character{ public float Health { get { return m_Health; } set { if( value < 0.0 ) m_Health = 0.0; if( value > 1.0 ) m_Health = 1.0; else m_Health = value; } } protected float m_Health;}
Now you'll see that validation/correction of the protected data happens EVERY TIME someone modifies it, automagically, without the need to make explicit calls to a validation function.
As well, the conversation can go the other way as well. Although I dont have time to provide an example now, while validation gives the class an opportunity to make sure the data coming in is correct, formatting or conversion allows the class to make sure that data is being exposed to the user in an easy-to-use format.
Lets say a protected field of a class is some other complex class, however I dont want to expose all parts of it to the users, or I want to format it as a string, integer, etc...I can easily provide an accessor to the protected data which returns a nicely formatted value instead of a direct reference to the complex, user-defined type.
So here they are in a nutshell. Getters/Setters...
- Decrease coupling, allowing easier maintenance
- Increase encapsulation, allowing more flexible development
- Allow for procedurally generated data
- Allow for automatic validation
- Allow for automatic conversion and/or formatting
Cheers!