Don't expose mutable attributes

From CSSEMediaWiki
Jump to: navigation, search

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. It can also be viewed as a less extreme version of the Law of Demeter which applies only to write operations.

Contents

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.

Java

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.

C++

In C++ you can return const references to your collection, for example:

const & std::list<Students> getStudents() const {
   return students;
}

The first const is forbidding any use of non-const methods on the list, which mean you will have to use const_iterator for example.

See Also

Personal tools