The code for this part of the lecture can be found here.
Until now all methods produced a new instance of the object. the only exception has been the construction of circularly referential data, wehre we needed to change the state of the object after it has been created.
There are other situations where the value the object represents has to change after the object has been constructed. We call this mutation. We say that the methods that cause such change have side effects.
We will discuss the design of methods that cause side effects using as an example a list of phone numbers. Let's start with examples.
Matt : Wendy 1234 Dan 8768 Pat 6284 Dan : Matt 7999 Judy 1833 Erna 3325 Rob : Wendy 1234 Pat 6289 Matt 7999
We'll need a phone entry that will hold the name and number of a person. We will also need a list of phone numbers that will keep a list of contacts for a person.
+----------------+ | IPhList | +----------------+ | / \ --- | ----------------------------- | | +----------------+ +----------------+ | MtPhList | | ConsPhList | +----------------+ +----------------+ +--| PhEntry first | | | IPhList rest | | +----------------+ | V +----------------+ | PhEntry | +----------------+ | String name | | int num | +----------------+
Now, let's add the method changeNum
to PhEntry
.
... // create a new PhEntry with the same name and num as the phone number. public PhEntry changeNum(int num){ return new PhEntry(this.name, num); }
Consider the scenario where we have the following lists of phone numbers.
IPhList mattlist = new ConsPhList(wendy, new ConsPhList(dan, new ConsPhList(pat,mt))); IPhList danlist = new ConsPhList(matt, new ConsPhList(judy, new ConsPhList(erna,mt))); IPhList roblist = new ConsPhList(wendy, new ConsPhList(pat, new ConsPhList(matt,mt)));
Wendy's phone number has changed and we would like to have this
change reflected in our example. Using updateNum
creates a new instance with the name Wendy and the new number,
e.g. PhEntry wendy2 = wendy.changeNum(4321);
. This
does not update the previous instance for wendy in the two lists
mattlist
and roblist
. We would like to
have the update to wendy's instance be visible to the lists that
have wendy as a member. The effect of the method should
be the change of Wendy's phone number everywhere where her phone
record is known.
// EFFECT: update the phone number for this PhEntry public void changeNum2(int num){ this.num = num; }
The return type of our method is void
, that is, it
returns nothing back. The execution of this method is used for
its side effects. It mutates the state of the instance by updating
the field num
.
We now have a problem. We cannot test this method by comparing the value it produces with the expected value. Instead, we can only observe and test the efect of the method on an existing instance of the class. Therefore our tests will consist of three parts:
Typically the three steps are composed into a test method, or the setup part is shared by several test methods.