On completion of this page you will know how to configure a class so that external code cannot corrupt its contents. In our example this will be achieved by ensuring that incoming data fall between given values and any data items outside of those values will be rejected.
On the previous page we made some attempts to protect the internal data of the class from being corrupted accidentally or deliberately by external code. The single measure we have taken towards this goal has been to make the class' data members private so that only methods within the class could access them and change their values.
Of course programming code does not exist in isolation - it also requires data to operate on. Also the data a program operates on is generally in a specific format or within a range of values. In our case that data for the class' object to operate on is supplied while the object is being created as shown in lines 80 to 84 below. Our previous example had no means of either eliminating or rejecting inappropriate data. Therefore we still have no protection against someone creating an object of the class Employee as follows: myPay = Employee("135531", "Joe Bloggs", 5000, 6000) and then doing a disappearing act before the crime was discovered.
How do we protect our data from situations similar to this? The answer is to restrict the values for hours and rate to acceptable ranges.
For our example here we will assume that the class we have been dealing with up to now is aimed at being used by an organisation that pays its employees weekly and also pays them at an hourly rate rather than a fixed salary. We will also assume the following policies:
the minimum number of hours worked by an employee in any week is five.
for health reasons the maximum number of hours an employee is allowed to work in any one week is 60.
the lowest hourly rate paid to an employee is $20
the highest hourly rate paid to an employee is $80
From the above we can deduce that for any object the value for hours must be in the range 5 to 60 and the value for the hourly rate must be in the range 20 to 80.
We shall now examine Listing 2 below to see how those controls are implemented.
Looking at line 9 of Listing 1 we have added an extra data member __blnValidData. This is a Boolean data member which will have a value of True if the data received is correct and of False if the data is incorrect. When the values for hours and rate are received, they will be checked for being within the correct ranges. If both values are within the correct range then __blnValidData will be set to True, otherwise it i set to False. If it is True the the class' code will assume that the input and processed data are correct and the modules in the range 20 to 60 will return the values of the data items, otherwise they will return either blanks or negative values to indicate that the object contains incorrect data. Checking that the values for hours and rate takes place in the constructor, which now spans lines 11 to 18.
The number and type of the arguments passed to the constructor remain the same as the previous example but the body consists of an if construct. Here we are ensuring that the value of the hours worked must be in the range 5 to 60 inclusive and that the value of the hourly rate must be in the range 20 to 80 inclusive. Thus the condition at line 12 is that hours is greater than or equal to five and less than or equal to 60 and that the rate is greater than or equal to 20 and less than or equal to 80. If all of those conditions are met then we have correct data for our object and therefore lines 13 to 18 will be executed. Lines 13 to 16 are the same as in the previous example, i.e. the ird number, name, hours and rate are copied into the object's data members. At line 18 the data member __blnValidData is set to True to indicate to subsequent users of the object that the data contained therein is valid. Finally the method __calculate() is called at line 18.
Of course if either of the hours or rate were outside of the allowed range, the condition at line 12 would be false and thus lines 13 to 18 would have been skipped. This would have resulted in the string data members having a value of blank and the numeric data members have a value of zero. Also the data member __blnValidData would have a value of False.
The rest of the class' methods test the value of __blnValidData to determine which action to take.
The method irdValue() spans lines 20 to 24. Line 21 tests __blnValidData for being true. If it is then line 22 is executed and the value of the ird is returned, otherwise line 24 is executed and a blank is returned. The method nameValue() works exactly the same way except that the employee's name is returned if __blnValidData is true.
The method hoursValue() at lines 32 to 36 tests __blnValidData for being true. If it is then the value of the hours worked is returned at line 34, otherwise -1 is returned at line 36. The other methods in the range lines 38 to 60 work in the same way.
The method toString() spans lines 67 to 78. At line 68 the data member __blnValidData is tested for being true. If it is then lines 69 to 75 are executed, thus building up the local string variable strOutput to contain the labelled values of the object's data members, otherwise these lines are skipped and an error message is stored in strOutput line 77.
The code spanning lines 80 to 89 is external to the class. The first five lines create separate objects of the class Employee. Line 81 passes invalid data - the hours are too low. Line 82 also passes invalid data because the rate is too high. Lines 80, 83 and 84 pass correct data.
The purpose of Encapsulation is to protect the integrity of an object's data. On the previous page we partially achieved this by making the data members private as well as some of the methods that processed them. On this page we extended the concept of Encapsulation to ensuring that only correct data was passed to the newly created object. This took place mainly in the object's constructor where the hours was checked for being in the range 5 to 60 and rate in the range 20 to 80. If both fall within those ranges then the object's data members are populated with the incoming data, the gross, tax and net are calculated and a Boolean variable __blnValidData is set to True
The value of this variable informs the rest of the object's methods if correct data has been received. If the data is correct then the values of the appropriate data item or items is returned to the external program, otherwise blanks or negative numbers are returned indicating invalid data.
Copy the code from lines 1 to 79 of Listing 1 into a code editor and save it. Now make the following changes to it:
Create an object of the class Employee and pass the values "121212", "Mike Hammer", 20, 20 to it. Check the output by using the toString() method.
Create another object of Employee and make up your own values to pass to it. Ensure that they are within the correct bounds. Now use the methods between lines 20 and 60 to display the values of the data methods. An example of this would be print("Employee name ", objectName.nameValue()
What is the purpose of the double underscore in the names of the data members declared at lines 2 to 9?
In the same group of variables what different data types are there?
Regarding the method that spans lines 11 to 18:
what is this method normally called?
what purpose does the method serve?
can this method be called from code outside of the class?
What is the purpose of the data member __blnValidData
Name the object methods that use the value of the above data member to determine what course of action to take.
If this line was added to the external code of Listing 1:payroll5 = Employee("678678","Joe Bloggs",30,45) what would be the value of the internal data members once the method that spans lines 11 to 18 has finished execution