Inheritance
[Agent practical 4 of 9]
Next, we'll look at the new Agent interface.
Here it is:
Download it to your practical directory and open it in Notepad++.
You should be able to see that on the one hand, the interface is extremely simple -- it's just empty stubs for the methods that should be implemented. Yet, on the other hand, the fact that we could do this kind of thing in Model.java:
private Agent[] agents = new Agent[numberOfAgents];
for (int i = 0; i < 5; i++) {
agents[i] = new Nibbler(world);
}
for (int i = 5; i < agents.length; i++) {
agents[i] = new Predator(world);
}
for (int i = 0; i < numberOfIterations; i++) {
for (int j = 0; j < numberOfAgents; j++) {
agents[j].run();
}
}
makes the use of interfaces incredibly powerful in terms of keeping models flexible.
So, the interface only really defines something that runs and reports where it is. The reporting is just so we can
keep track of the agents (and, ultimately, draw them on the screen). All of this is sufficiently generic that
any given agent is probably going to need to do it. Given this, we can extract all this into an relatively generic class that
does these jobs for us and implements the interface. This is what "Animal
" does. Here it is:
Download it to your practical directory and open it in Notepad++.
Notice a few things about this class.
Firstly, note it implements the interface Agent
.
Secondly, its run
method doesn't actually do anything. Now, we could have declared the class abstract and the
run method as one that subclasses had to provide themselves, however, its quite useful early in model development to have a relatively
simple agent class you can build (unlike the interface) but that just acts as a placeholder while you get the rest of the
model working. So, you can make objects of this class, but they don't do a lot. Any subclass will probably supply its own
run
method, which will override this one.
Thirdly, note that the class supplies the basic elements of storage and reporting we want. It can be set up with
a copy of the Environment using its constructor, and has a default x
and y
, with the
associated accessor methods dictated by the interface.
Finally, note that the instance variables are set as protected
. This means they are unavailable to
all external classes, except classes that subclass Animal
. This means our Nibbler
class will
be able to directly access x
, for example, rather than having to call getX()
as it would if
x
was set to private
in this superclass.
Once you're happy you understand this, let's move on to look at our Nibbler class.