In a way, an object-oriented program is like an ecosystem and objects are like organisms. To maintain a thriving ecosystem, organisms must interact. The same is true in OOP. To have a useful program, objects must interact in well-defined ways. In OOP-speak, objects interact by sending messages to each other. What they do on a practical level is invoke each other's methods. That may sound a little impolite, but it's actually much more courteous than if an object were to access another object's attributes directly.
The Alien Blaster program simulates an action game where a player blasts an alien. In the program, a hero blasts an invader and the invader dies (but not before giving a grand farewell speech). The program accomplishes this when one object sends another a message. Figure 9.2 shows the results of the program.
Figure 9.2: The battle description is the result of objects exchanging a message.
Technically what happens is that the program instantiates a Player object, hero, and an Alien object, invader. When hero's blast() method is invoked with invader as its argument, hero invokes invader's die() method. In English, this means that when a player blasts an alien, the player sends a message to the alien telling it to die. Figure 9.3 provides a visual representation of the message exchange.
Figure 9.3: hero, a Player object, sends invader, an Alien object, a message.
The diagram I created to show two objects exchanging a message is a pretty simple one. But with many objects and many relationships among them, diagrams like this can become complex. In fact, there are a variety of formal methods for mapping software projects. One of the most popular is the Unified Modeling Language (UML), a notational language that is especially useful for visualizing object-oriented systems.
Here's the program listing for Alien Blaster:
# Alien Blaster # Demonstrates object interaction # Michael Dawson - 4/10/03 class Player(object): """ A player in a shooter game. """ def blast(self, enemy): print "The player blasts an enemy.\n" enemy.die() class Alien(object): """ An alien in a shooter game. """ def die(self): print "The alien gasps and says, 'Oh, this is it. This is the big one. \n" \ "Yes, it's getting dark now. Tell my 1.6 million larvae that I loved them... \n" \ "Good-bye, cruel universe.'" # main print "\t\tDeath of an Alien\n" hero = Player() invader = Alien() hero.blast(invader) raw_input("\n\nPress the enter key to exit.")
Before you can have one object send another object a message, you need two objects! So, I create two in the main part of the program through the following lines:
hero = Player() invader = Alien()
The first line creates a Player object and assigns it to hero. The second line creates an Alien object and assigns it to invader.
The next line of code invokes hero's blast() method:
hero.blast(invader)
There's something new going on in this line. In the method call, I list invader as an argument. By examining the definition of blast(), you can see that it accepts this value into its parameter enemy:
def blast(self, enemy):
This just means that, in this method, the Alien object is called enemy. While this method executes, enemy refers to the same object as invader does in the main part of the program.
After displaying a message, blast() invokes the Alien object's die() method through the following line:
enemy.die()
The Player object is sending the Alien object a message, telling it to die.
The Alien object receives the message from the Player object in the form of its die() method being invoked. The die() method is pretty simple. All it does is display a melodramatic good-bye, which appears as follows:
The alien gasps and says, 'Oh, this is it. This is the big one. Yes, it's getting dark now. Tell my 1.6 million larvae that I loved them... Good-bye, cruel universe.'