Methods
[Agent practical 3 of 9]


This practical we're going to clean up our code, making accessor and mutator methods for all the key variables that need exchanging, and adding a "run" method to our Agents that encapsulates their behaviour. First, though, we're going to build some constructor methods for all our classes, to help with tying all the objects together.

Note that with this practical it is worth reading each page completely before attempting any given section of it.


 

Start, as last practical, by copying your java files from the last practical to a new directory: java\src\unpackaged\framework3 -- keep a copy of the old files in last practical's directory: don't delete them, but work on the new copies.


First, we'll sort out the structure of our main Model class.

At the moment, you probably have something like this (with code replacing the comments):

class Model {

   public static void main (String args[]) {

      int numberOfAgents = 3;
      int numberOfIterations = 10;
      Agent[] agents = new Agent[numberOfAgents];

      // Code to set up the agent array
      // Loop to fill the agent array

      Environment world = new Environment();

      // Code to set up the Environment
      // Nested loops to fill the Environment's data array with 255s.
      // Code to run the model.

   }

}

The problem with this is that main is static. We've carefully planned the practicals so far so this hasn't been a problem, but if we get any more complicated, things will start to become difficult in a static context. Given this, now change your code so that it uses the 'sleight of hand' of having everything in the Model constructor, thus:

public class Model {

   private int numberOfAgents = 3;
   private int numberOfIterations = 10;
   private Agent[] agents = new Agent[numberOfAgents];
   private Environment world = new Environment();

   public Model() {
      // Code to set up the agent array
      // Loop to fill the agent array
      // Code to set up the Environment
      // Nested loops to fill the Environment's data array with 255s.
      // Code to run the model.
   }

   public static void main (String args[]) {
      new Model();
   }

}

There are a few things to note about this. Firstly, note that we've now removed our hardwired variables and our two major data structures from the rest of the code. They now reside at the top of our class, within the class block but outside of the method blocks like main or the constructor. These are now 'instance variables' -- variables that are created once, when the object is created, and exist all the time the object exists.

The fact that instance variables are created with the object is not so important in the main class, but instance variables are a key element of other classes. Infact, if you look at Environment and Agent, you'll see that the variables we created in these are all instance variables, which is how we've been able to use them -- they've been created with the agents and the world object.

To come back to a comment from the last practical, in general it is good practice to put all hardwiring variables at the top of the class in this fashion (not in the main block, as we had before). In this area, they are easy to find, but the other advantage is that their scope is the whole class, which means they can be used in other methods within the class (except in main, as main is static and can only use non-static variables declared within itself). This is also the reason we've extracted out the two major data storage objects: the agents array, and the world. By putting them as instance variables, they are available for other methods in the class, should we want to use them. If they were declared in a method, they'd only be available in that method. We'll see how useful this is when we come to drawing the location of the agents and the world data later in the course.

The second thing to note about the new structure is that we can now add the proper access control. Our class is public, as is our constructor, while our instance variables are private to stop other classes directly influencing them.

Make the changes above and then recompile and rerun your code to make sure it works.


Next, go on to the next section, where we'll make constructors for our other two classes.