Getters and setters

From CSSEMediaWiki
(Difference between revisions)
Jump to: navigation, search
(tedious background explanation of getters & setters added.)
m (Reverted edits by Ebybymic (Talk); changed back to last version by Joey Scarr)
 
(11 intermediate revisions by 6 users not shown)
Line 1: Line 1:
<Long tedious background explanation of getters & setters goes here>
+
Riel's heuristic 2.1, [[Hide data within its class]], implies that data members (i.e. fields) of a class should never be directly accessible by external entities. Getters and setters are often used to get around this problem, by providing methods that allow external classes to retrieve and change the data indirectly.
  
* A 'Getter' also known as ''accessors'' are methods that return a vaue to the caller.
+
The extra layer of abstraction has a number of advantages: for example, the programmer can provide read-only access to a piece of data by providing a getter for it, but not a setter. Furthermore, they are a good way to [[Encapsulate that which varies]]: they provide an interface that can remain constant even if the underlying data model changes slightly within the class. They also allow classes to include validation code or anything else that might be necessary when setting the value of a field.
  
* A 'Setter' also known as ''mutators''are methods that that set a value for the caller.
+
'Getters' are also known as ''accessors'', and are methods that return a value to the caller. 'Setters' are also known as ''mutators'', and are methods that set a value in the receiver. It's worth noting that C# provides built-in support for getters and setters via "properties", which provide a convenient field-like syntax while retaining the fine-grained control of method calls.
  
The two should not be combined as this creates unexpected side effects for the unsuspecting developer. This idea is callse [[Command query separation]].
+
Getters and setters should never be combined, as this creates unexpected side effects for the unsuspecting developer. This idea is called [[Command query separation]].
  
Using setters rather than having direct access to fields is good practice. It allows the class to maintain the integrity of the data enforce constraints, if there are any, on exactly what values can be set.
+
Using setters rather than having direct access to fields is good practice. It allows the class to maintain the integrity of the data by enforcing constraints, if any, on exactly what values can be set.
  
====The problem with getters====
+
==The problem with getters==
Using getters can be useful for [[Ken Auer 1995|Reusability through self-encapsulation]]. It can however be misused very easily. The purpose of a getter is to retrieve information. If getters are mostly being used from outside the class to get access to member variables one should ask why is [[Keep related data and behavior in one place|data and functionality not in the same place]].
+
Using getters can be useful for [[Ken Auer 1995|Reusability through self-encapsulation]]. However, it can be misused very easily. The purpose of a getter is to retrieve information. If getters are mostly being used from outside the class to get access to member variables one should ask why is [[Keep related data and behavior in one place|data and functionality not in the same place]].  It may be that you are getting out values to do work that the class should be doing for itself.  This sometimes leads to breaking the [[Law of Demeter]]. In cases like this it is better to [[Tell, don't ask]].
  
There is also the possibility that you are Getting out values to do work that the class should be doing for itself. This sometimes leads to breaking the <reverb> [[Law of Demeter]] </reverb> In cases like this it is better to [[Tell, don't ask]].
+
==The alternative to setters==
 +
There is an alternative to setters: ''[[Immutable object|immutable objects]]''. Many programmers will already be familiar with this concept since Java, C# and other languages make strings immutable. The value of an immutable object is set at creation and cannot be changed. This guarantees that there are no side effects. Many concepts will not work without the concept of immutable objects such as [[flyweight]] and the "canonical representation" mechanism for strings in Java.
  
The above is just two ways of saying the same thing.
+
==Guidelines for good getter/setter design==
====The alternative to setters====
+
====Version 1====
There is an also alternative to setters. That is ''immutable objects''. Many programmers will already be using this concept in there programming as Java, C# and other languages force immutable strings on the programmer. The value of an immutable object is set at creation and can not be changed. This means no side effects. Many concepts will not work without the concept of immutable objects such as [[flyweight]] and the "canonical representation" mechanism for strings in Java.
+
 
+
'''Rule for good design, version 1:'''
+
 
* Whenever you declare a field, ''foo'', make it private.
 
* Whenever you declare a field, ''foo'', make it private.
 
* Add a public getter called ''getFoo()'', or ''isFoo()'' for booleans.
 
* Add a public getter called ''getFoo()'', or ''isFoo()'' for booleans.
Line 26: Line 24:
 
* Elsewhere, use the getters & setters.
 
* Elsewhere, use the getters & setters.
  
Simple.
+
Simple. Except we just killed [[Encapsulation]].
  
Except we just killed [[Encapsulation]].
+
====Version 2====
 +
* As above, but only add the getters and setters as necessary.
  
'''Rule for good design, version 2:'''
+
If the type or name of foo changes, we can keep the methods the same and avoid the propagation of this change.  By doing this we are [[Information hiding|hiding information]] and [[Encapsulate that which varies|encapsulating change]].
* As above, but only add the getters &/or setters as necessary.
+
  
If the type or name of foo changes, should we change the methods too?
+
====Version 3====
 +
* As above, but always use the getters & setters, even within the object containing the field.
  
If we do, are we [[Information hiding]]?
+
This suggests that the only methods allowed to touch the field directly are the getters & setters themselves.
 
+
Some gurus go further, suggesting that we should always call getters & setters, even from inside the object containing the field.  The only methods allowed to touch the field directly are its getter & setter.
+
 
+
'''Rule for good design, version 3:'''
+
* As above, but always use the getters & setters.
+
  
 
This idea is explained by [[Ken Auer 1995]].  But first, it helps to realise there is more than one [[Encapsulation boundary]] behind which we might hide fields.
 
This idea is explained by [[Ken Auer 1995]].  But first, it helps to realise there is more than one [[Encapsulation boundary]] behind which we might hide fields.
  
 
== See Also ==
 
== See Also ==
[[Hide data within its class]]
+
*[[Hide data within its class]]
 
+
*[[Keep related data and behavior in one place]]
[[Keep related data and behavior in one place]]
+
*[[Avoid protected data]]
 
+
*[[Riel's heuristics]] 9.2 Do not change the state of an object without going through its public interface.
[[Avoid protected data]]
+
*[[Don't expose mutable attributes]]
 
+
*[[Getter and setter policy]]
[[Riel's heuristics]] 9.2 Do not change the state of an object without going through its public interface.
+

Latest revision as of 03:23, 25 November 2010

Riel's heuristic 2.1, Hide data within its class, implies that data members (i.e. fields) of a class should never be directly accessible by external entities. Getters and setters are often used to get around this problem, by providing methods that allow external classes to retrieve and change the data indirectly.

The extra layer of abstraction has a number of advantages: for example, the programmer can provide read-only access to a piece of data by providing a getter for it, but not a setter. Furthermore, they are a good way to Encapsulate that which varies: they provide an interface that can remain constant even if the underlying data model changes slightly within the class. They also allow classes to include validation code or anything else that might be necessary when setting the value of a field.

'Getters' are also known as accessors, and are methods that return a value to the caller. 'Setters' are also known as mutators, and are methods that set a value in the receiver. It's worth noting that C# provides built-in support for getters and setters via "properties", which provide a convenient field-like syntax while retaining the fine-grained control of method calls.

Getters and setters should never be combined, as this creates unexpected side effects for the unsuspecting developer. This idea is called Command query separation.

Using setters rather than having direct access to fields is good practice. It allows the class to maintain the integrity of the data by enforcing constraints, if any, on exactly what values can be set.

Contents

The problem with getters

Using getters can be useful for Reusability through self-encapsulation. However, it can be misused very easily. The purpose of a getter is to retrieve information. If getters are mostly being used from outside the class to get access to member variables one should ask why is data and functionality not in the same place. It may be that you are getting out values to do work that the class should be doing for itself. This sometimes leads to breaking the Law of Demeter. In cases like this it is better to Tell, don't ask.

The alternative to setters

There is an alternative to setters: immutable objects. Many programmers will already be familiar with this concept since Java, C# and other languages make strings immutable. The value of an immutable object is set at creation and cannot be changed. This guarantees that there are no side effects. Many concepts will not work without the concept of immutable objects such as flyweight and the "canonical representation" mechanism for strings in Java.

Guidelines for good getter/setter design

Version 1

  • Whenever you declare a field, foo, make it private.
  • Add a public getter called getFoo(), or isFoo() for booleans.
  • Make the return type of the getter the same as the field.
  • Add a public setter called setFoo() & pass a parameter of foo's type.
  • Inside the object, access the field directly.
  • Elsewhere, use the getters & setters.

Simple. Except we just killed Encapsulation.

Version 2

  • As above, but only add the getters and setters as necessary.

If the type or name of foo changes, we can keep the methods the same and avoid the propagation of this change. By doing this we are hiding information and encapsulating change.

Version 3

  • As above, but always use the getters & setters, even within the object containing the field.

This suggests that the only methods allowed to touch the field directly are the getters & setters themselves.

This idea is explained by Ken Auer 1995. But first, it helps to realise there is more than one Encapsulation boundary behind which we might hide fields.

See Also

Personal tools