Spatial Interaction Modelling: Structuring into methods
[Practical 5 of 11 - Part 1]


Refactoring Data Load:

The first part to refactor is the way we load and access the data for the model. We want to separate out the complexities of data access from the model running. This way if we change how the data is loaded we don't end up changing the rest of the program. This is what is referred to as loose coupling . Figure 1 shows the code we are concerned with.

Data loading code highlighted.
Figure 1

First we need a class to put the code in. Right click on the SIM package in the Projects area of the IDE as shown in Figure 2. Select New >> Java Class...

Creating the new DataHandler class.
Figure 2

In the New Java Class wizard window that opens type in the class name DataHandler as shown in Figure 3 and click finish.

Creating the new DataHandler class wizard screen 2.
Figure 3

Copy the code highlighted in Figure 1 from our SpatialInteractionModel class and paste it into the new DataHandler class between the class opening and closing braces shown highlighted in Figure 4.

Don't worry about the red lines that appear in the SpatialInteractionModel class. This is Netbeans letting us know that it has found code that will not compile before we even try to... The really handy aspect of this feature is that it even shows you where the error is in the class just like a spell-checker. We will come back and solve these issues in a moment.

All load data code pasted into the DataHandler class.
Figure 4

One of the reasons why we are refactoring our code is to make it more flexible in the future. One of the ways we can do this is by breaking the code down into small units that undertake a certain function. These are called methods. The first thing we are going to do is create a method that we will call to load our data.

Insert the line of code public void loadData(){ below the class declaration and above the code we have just pasted into the class as shown in Figure 5. And place the closing brace for the new method below the pasted code and above the class closing brace. The brace positions for the new method are shown highlighted in yellow in Figure 5.

Make sure that the new method declaration is tabbed in once more than the class declaration, we are inside the class block. Also make sure the pasted code is tabbed in once from the method declaration that it is now inside. If we don't get the tabbing correct, the code would still run but it would be much less readable and difficult to follow when trying to find bugs.

Inserting the dataLoad method into the DataHandler class.
Figure 5

Netbeans tries to be helpful with braces and tabbing. If you paste the line above into the text editor and press return, Netbeans will automatically put a closing brace in place for you and set your indented tab location for the next line of code within the new block. I say it tries to be helpful, it doesn't always do what you want, after all its not mind reading software its just an IDE! Be careful that Netbeans doesn't help you end up with too many closing braces though.

Tip: you can check brace pairs by putting your cursor on either the opening or closing brace, both braces in the pair will be highlighted for you.

Although we have placed our arrays in a new class inside a data load method we can't do anything with them. The arrays that are created inside the method are not available to anything outside of that method. They have method level scope.

We need to be able to access the data in our model so we need to change this scope. First of all declare three new array variables below the class declaration and above any method declarations, this makes them instance level variables, they will turn green in Netbeans to show this. Assign null to each of the variables.

Unfortunately, we cannot declare the variables at one level and then use the declare, construct and initialise notation in the method because the variables have already been declared at the instance level. There is a way around this. Array variables are labels we put on an object stored in a location in the computer memory. We can create the arrays locally and then assign an instance level label on them and they become an instance level variable! Under each of the array declarations in the loadData method we add a line to assign the locally declared, initialised and constructed array to our instance variable.

The key word this simply means that we are using an instance variable form this object. Notice the variables used after the key word this are all green.

Creating the instance level data variables.
Figure 6

This is all good but it hasn't helped our access to the data. All of our instance level arrays are declared private which means nothing outside of this object can access them. So why do that? Why not just declare them public? We may want to do some manipulation of the values coming out of the arrays or check validity before we use them in the model. This is easier to do in one place, when we access the data, rather than in multiple places when we request the data in other objects. Therefore, we will use an accessor method to get at the data.

It is relatively painless to do this in Netbeans. Select the option to Encapsulate Fields... from the Refactor menu. There are lots of 'helper' items in the refactor menu but the encapsulate option is one of the most useful time savers.

Refactoring using Netbeans automated functionality.
Figure 7

Once you have selected the Encapsulate Fields... option you will see the window in Figure 8. We only want to be able to get data not set it, so check the three boxes next to the variables in the Create Getter column. Select the Insert Point: to be After loadData() : void. leave the rest of the options as the default making sure the Fields' Visibility: (variable) is private and the Accessors' Visibility: (the method created to access the variable) is public.

Once you are done click Refactor.

Encapsulate fields dialog.
Figure 8

You should now see three new methods below the dataLoad method that we added that have been automatically generated by the IDE for you. This is good but the comments are poor, add a little more description.

New getter methods added.
Figure 9

Returning a two dimensional array for the distances ties our code to always having an array to return. However, if we wanted to calculate the distances between origin and destination points as a Euclidean distance at runtime, a common approach, then the array may not exist.

To get around this we are going to adapt the accessor method to return a single double value for the distance between two points identified by two parameters of the origin and destination. If a user presents a parameter value that falls outside of the valid index values an IndexOutOfBoundsException would result.

To ensure this situation does not arise we test each index parameter to make sure it is valid. If either is invlaid -1.0 will be returned by the accessor method. See Figure 10 for the detailed code changes and accompanying comments, implement these changes in your accessor method.

Adjust the getter method for the distances.
Figure 10

Adjusting the Model Code:

Create a second new empty class called Model, following the same process as above with the DataHandler class. Create two methods in the new class called calculate and calculateBalancingFactors.

Declare the calculate method as a void with public access. Declare it so that it takes in two parameters alpha and beta both of type double.

Declare the calculateBalancingFactors method as a void with private access. Declare it so that it takes in two parameters originChanged and destinationChanged both of type boolean.

Have a go at creating the methods yourself, when you have finished your class should look something like the one in Figure 11.

Creating the Model class.
Figure 11

Cut the code that calculates the Ai balancing factor out of the class SpatialInteractionModel shown highlighted in Figure 12.

Moving the balancing factor code stage 1.
Figure 12

Paste the code into the calculateBalancingFactors method in the new Model class as shown in Figure 13. Make sure that the code is tabbed to the correct indentation within the method block.

Moving the balancing factor code stage 2.
Figure 13

Cut the remaining model equation out of the SpatialInteractionModel class as shown in Figure 14.

Moving the model equation code stage 1.
Figure 14

Paste the code into the calculate method in the new Model class as shown in Figure 15. Make sure that the code is tabbed to the correct indentation within the method block.

Moving the balancing factor code stage 2.
Figure 15

This first section of the practical has dealt with splitting the spatial interaction modelling code into two different classes. One to run the model and one to deal with the data loading and provide controlled access to the data.

The next section of the practical will walk through the stages required to complete the refactoring process removing the errors introduced through splitting the code across two different classes.

Continue to part 2 of the practical