Don't expose mutable attributes

From CSSEMediaWiki
(Difference between revisions)
Jump to: navigation, search
(New page: ''Mutable - Changeable; inclined to mutate.'' [http://en.wiktionary.org/wiki/mutable wiktionary.org] This design maxim states that a class should not expose objects that can be changed. T...)
 
m
Line 1: Line 1:
 
''Mutable - Changeable; inclined to mutate.'' [http://en.wiktionary.org/wiki/mutable wiktionary.org]
 
''Mutable - Changeable; inclined to mutate.'' [http://en.wiktionary.org/wiki/mutable wiktionary.org]
  
This design maxim states that a class should not expose objects that can be changed. The idea is that the class itself should control access to it's attributes. If a class wishes to make modifications to another classes attribute(s) it should be done through a method of the class that changes the attribute, rather than getting the attribute itself and then changing it.
+
This design maxim states that a class should not expose objects that can be changed. The idea is that the class itself should control access to it's attributes. If a class wishes to make modifications to another classes attribute(s) it should be done through a method of the class that the attribute belongs to, rather than getting the attribute itself and then changing it.
  
 
This is closely related to [[Riel's heuristics]] 9.2  - Do not change the state of an object without going through its public interface.
 
This is closely related to [[Riel's heuristics]] 9.2  - Do not change the state of an object without going through its public interface.
Line 33: Line 33:
 
  course.getStudents().add(dumbStudent);
 
  course.getStudents().add(dumbStudent);
  
doing this circumnavigates the access control (IQ requirement), so we can no longer be sure the students collection only contains what we expect (Students with IQ > 120). This could lead to runtime errors if other code assumes such conditions will always be true.
+
This circumnavigates the access control (IQ requirement), so we can no longer be sure the students collection only contains what we expect (Students with IQ > 120). This could lead to runtime errors if other code assumes such conditions will always be true.
  
 
* Even worse, the setStudents method allows any class to completely change who is taking the course. This means the Course class has no control over it's private attribute, which is obviously not good.
 
* Even worse, the setStudents method allows any class to completely change who is taking the course. This means the Course class has no control over it's private attribute, which is obviously not good.

Revision as of 04:45, 18 July 2009

Mutable - Changeable; inclined to mutate. wiktionary.org

This design maxim states that a class should not expose objects that can be changed. The idea is that the class itself should control access to it's attributes. If a class wishes to make modifications to another classes attribute(s) it should be done through a method of the class that the attribute belongs to, rather than getting the attribute itself and then changing it.

This is closely related to Riel's heuristics 9.2 - Do not change the state of an object without going through its public interface.

Example

A course has a collection of students, and only students with an IQ of 120 or more can join the class. However, the programmer in this case has a habit of always generating the default getters and setters for each attribute.

Collection<Student> students;

...

public addStudent(Student student) {
  if(student.IQ > 120) {
    students.add(student);
  }
}

public Collection getStudents() {
  return students;
}

public void setStudents(Collection newStudents) {
  students = newStudents;
}

This situation causes two problems:

  • Although only students with an IQ of 120 or more are allowed in this course, there is nothing to stop an external class performing the following:
course.getStudents().add(dumbStudent);

This circumnavigates the access control (IQ requirement), so we can no longer be sure the students collection only contains what we expect (Students with IQ > 120). This could lead to runtime errors if other code assumes such conditions will always be true.

  • Even worse, the setStudents method allows any class to completely change who is taking the course. This means the Course class has no control over it's private attribute, which is obviously not good.

Solution

The obvious solution to this is to not use getters or setters, and provide controlled access to the attribute through methods. However, in some cases, a getter that returned a read-only copy of the attribute would be useful. Fortunately, Java provides a simple way to do this. The above getStudents method could be re-written as such:

public Collection getStudents() {
  return Collections.unmodifiableCollection(students);
}

This returns an unmodifiable view of the students collection, which can be used for "read-only" purposes. This should probably be used for every getter that returns a collection (or other mutable attributes such as String). If you find yourself needing a getter that returns something with write-access, you should probably reconsider your design.

See Also

Personal tools