Quite simply, when designing a new class, how do I figure out what the invariant should be? What defines the invariant? I've heard that it's tied into validity, but that's still ambiguous. What makes a given instance valid or invalid is debatable.
Should I just go with my "gut" feeling? Are there guidelines for figuring out what the invariant is?
Invariant can be always represented as predicate with arguments being some or all state variables (fields) of the class. One class can have more then one invariant. For example, suppose you have an Account
class that has initialBalance
, listOfTransactions
, currentBalance
. Also, we keep the transactions in a sorted (by date) list . for This class there are at least two invariants that should be maintained:
1) initialBalance + sum(transaction amounts) = currentBalance
2) for every element in the listOfTransactions, the timestamp
of the transactions at position i
should be always less then the timestamp
of the transaction at position j
if i < j
.
Invariants depend on what the class
is doing and also how the class is implemented.
Let say, we can add one more state variable: closedDate
, and one more invariant will appear: no transaction can have date after the closeDate.
Or if the list is not sorted by date, but by transaction amount, then the invatians would change.
Another example:
Let's suppose that you have mutable Ellipse
class defined with two fields, r1
and r2
which has setters for r1
and r2
. This class doesn't have any invariant, as any values for r1 and r2 can represent well defined ellipse.
Now let's suppose that you create new Circle
class that extends the mutable Ellipse
. The circle has only one radius add the invariant would be (r1==r2). In order to maintain the invariant, you have to disallow somebody setting r1 or r2, such that r1!=r2 happens.
On the other hand if the Ellipse
and Circle
are immutable you don't have to care for the invariants during the life of the objects, as the condition would be checked only during construction.
With the previous examples, i wanted to explain that
1) the way the invariants are established and maintained depends very much on the choice of design of the relations between the classes.
2) What the class is doing
3) How the class is implemented.
Immutable classes tend to be less complex to maintain their invariant, as they are established at construction, and never change. (Immutability has many other benefits too - not in scope of the answer)