class employee {public: employee( int n = 0 ) : sal(n) { } employee* salary(int n) { sal = n; return this; } virtual long salary() { return sal; } protected: int sal; };
employee
k == (e->salary(k))->salary()
In slide object-invariant, we have defined a class employee. The main features of an employee are the (protected) attribute sal (storing the salary of an employee) and the methods to access and modify the salary attribute. For employee objects, the invariant (expressing that any amount k is equal to the salary of an employee whose salary has been set to k) clearly holds.
Now imagine that we distinguish between ordinary employees and managers by adding a permanent bonus when paying the salary of a manager, as shown in slide hidden-bonus. The reader may judge whether this example is realistic or not.
class manager : public employee {public: long salary() { return sal + 1000; } };
manager
k =?= (m->salary(k))->salary()
class manager : public employee {public: manager* bonus(int n) { sal += n; return this; } };
manager'
k + n == ((m->salary(k))->bonus(n))->salary()
-- A method m is a client of C if m calls a method of C
-- If m is a client of C then C is a supplier of m
-- C is an acquaintance of m if C is a supplier of m but not (the type of) an argument of m or (of) an instance variable of the object of m
screen->cursor()->move();
screen->move_cursor();
The guideline concerning the use of safe suppliers is known as the Law of Demeter, of which the underlying intuition is that the programmer should not be bothered by knowledge that is not immediately apparent from the program text (that is the class interface) or founded in well-established conventions (as in the case of using special global variables). See slide 4-demeter.
Do not refer to a class C in a method m unless C is (the type of)
1. an instance variable
2. an argument of m
3. an object created in m
4. a global variable