chapter three

3 Keeping objects consistent

 

This chapter covers

  • Keeping classes consistent
  • Emerging problems with inconsistent objects
  • Implementing pre-conditions and business validation mechanisms

A well-designed class encapsulates all its data and offers clients operations that either give a sneak peek at the data or manipulate them. These operations, when properly designed, make sure that the object is always in a valid state and that there are no inconsistencies. Better yet, they do so in a way that the clients of the class don’t even need to know about it.

Suppose a class that implements a shopping cart. Regardless of how many items the user adds or removes from it, the total amount to pay should match the price of each item times its quantity. Or, if the user removed the item from the cart, that item should be removed completely, and there shouldn’t be an item with quantity zero. These are just a few examples of what I mean by keeping state and consistency in the title of this chapter.

3.1 Make units of code responsible for their consistency

3.1.1 Ensure consistency inside the class

3.1.2 Ensure that complex consistency checks happen in a single place

3.1.3 Encapsulate state checks

3.1.4 Tell, Don’t Ask

3.2 Provide getters and setters that matter

3.2.1 Getters that don’t change state and don’t reveal too much to clients

3.2.2 Setters only to attributes that describe the object

3.3 Design aggregates explicitly

3.3.1 Create larger components to reduce interaction complexity

3.3.2 Don’t break the rules of an aggregate root

3.4 Design explicit data validation mechanisms

3.4.1 Make pre-conditions explicit

3.4.2 Create validation components

3.4.3 Use nulls carefully or avoid them if you can

3.5 Summary