Chapter 12. Objects and Classes
This chapter covers so-called object-oriented programming (OOP), which is new territory for many readers. We'll cover some of the terminology and show some applied examples to make it all concrete. You may have heard that OOP is some big mystery or that it's difficult to understand. Quite the contrary, the concepts are highly intuitive and the OOP process much easier than you may have been led to believe. At its heart, OOP simply means that you treat portions of your program as self-contained objects. This is easy to grasp once you realize that everything you deal with in the real world is a self-contained object. Your dog, your parents, your car, and your computer are all self-contained objects meaning that they do some things independently and do other things at your request even if you don't know the inner details of how they work.
You don't have to be a biologist to get your dog to fetch a stick; you don't need to be a mechanical engineer to drive your car; you don't need to be a psychoanalyst to interact with your parents; and rumors to the contrary, you don't need to be a computer scientist to check your email. All you need to know is the commands an object is willing to obey (which are called methods) and the results those commands produce. For example, if you press the gas pedal of your car, you can expect it to accelerate. If you tell your dog to sit, you can expect him to sit. Armed with this commonsense context of what an object is in the real world, let's see how to relate these concepts to ActionScript.
The classic example of a programming object is a bouncing ball. Like a real ball, a ball object can have properties that represent its attributes, such as its radius, color, mass, position, and bounciness (elasticity). To represent our bouncing ball in a program, we'll create a ball object with a radius property and so forth. The properties of an object represent its state at any given time, but some of its properties change over time. For example, to make our ball move, we need to simulate Newton's laws of motion. That is, we need to describe in computer terms how a ball moves over time. In the simplest case, recalling that speed multiplied by time equals distance, we can determine a ball's horizontal position in the future using this pseudoequation:
ball.xPosition += ball.xVelocity * (elapsedTime)
This equation starts with the ball's current position and adds the distance it has traveled (based on its velocity and the elapsed time) to come up with the new position. An object's behaviors are simply the rules that govern it, like our equation for calculating the position of the ball over time. We generally wrap these behaviors in so-called methods, which are simply the functions that implement an object's behaviors. For example, we might create a move( ) method that uses the preceding equation.
Therefore, methods can be thought of as the commands that an object obeys. Of course, an object can have multiple methods. Let's say we want to make our ball bounce. We can create a bounce( ) method that reverses the ball's direction and reduces its speed (our ball isn't perfectly elastic). The bounce( ) method might implement this equation:
ball.xVelocity = -(ball.xVelocity) * 0.95 // Ball is 95% elastic
Before getting into the esoterica of how to create objects, add properties, and implement methods, let's formalize some of our definitions. An object is technically a data structure that groups together related properties and methods (functions). An object typically encapsulates its behaviors, meaning that the internal details of how it performs its functions are not necessarily visible outside the object. Instead, a program can interact with an object via its so-called interfaces (i.e., methods that are publicly accessible outside the object). The rest of the program typically doesn't have to worry about how an object does what it does; instead, the program merely provides inputs to the object and checks the outputs (results) when applicable. You'll also hear talk of classes and instances . A class is simply a generic object category, and an instance is simply a specific case (i.e., a copy) of the object. For example, your particular pet dog is an instance of the generic Dog class. All dogs in the Dog class bark and have four legs, but your specific dog has its own particular values for the height, weight, and color properties used to describe dogs.
Object-oriented programming (OOP) is merely the name given to programs that make use of objects. Objects and OOP are so intrinsic to ActionScript that we've already used them, perhaps without your realizing it. A movie clip is a familiar object in Flash, and like all objects it is implemented as a collection of properties and methods. When we determine the height of a movie clip using someClip._height, we're accessing that clip object's _height property. And when we tell a movie clip to play using someClip.play( ), we're invoking that clip object's play( ) method.
Whether we create objects ourselves or use those built into ActionScript, OOP keeps the components of a program cleanly separated from one another (encapsulated ) and allows them to interoperate without knowing the details of other objects. This allows an object to change its internal functionality without adversely affecting other portions of the program that rely on the object, so long as the object's methods (i.e., its interfaces to the outside world) don't change. Returning to our ball object, for example, we don't care if the laws of physics change the behavior of our ball's motion. We just call the ball's move( ) method and let the object itself worry about the details.
Another nice feature of OOP is that we can treat different objects that have different behaviors in a uniform manner as long as they implement methods of the same name. For example, suppose we have a circle object and a square object. As long as both objects implement an area( ) method that returns the shape's area, we can call their area( ) methods without worrying about how each object calculates its own area.
In this chapter, we'll learn how to make a basic object, and we'll learn how to define a category of objects (i.e., a class). Once we're comfortable with the basics, we'll see how to share common characteristics between classes and objects (i.e., create a family tree) using inheritance. For example, we might implement a Horse class that along with our Dog class are descendants of the Mammal class. The Mammal class could implement methods and properties common to all mammals, such as the fact that they have hair, give milk, and are warm-blooded. Finally, we'll learn how OOP is used to control the Flash environment through ActionScript's built-in objects and classes.
12.1. The Anatomy of an Object
Like an array, an individual object is a container of containers. An array holds multiple data values in individual elements ; an object, analogously, holds multiple data values in individual properties. The properties of an object, however, are named, not numbered. An array stores a group of elements in a numbered list, but an object stores properties according to unique identifiers that are not arranged in any specific order. To access an array element, we need to know its numeric position, but to access an object property, we need to know its name (i.e., identifier).
Figure 12-1 depicts the properties of a sample object called ball. The ball object contains two properties: radius and color. The values of those properties are 50 and 0xFF0000 (the hex value of red). The properties are named with unique identifiers, much like variables. Even though each property has its own name, all are contained by the single encompassing object, ball.
Figure 12-1. A sample object structure
Obviously an object typically defines properties that are meaningfully related. More specifically, the properties of an object should be chosen in such a way that they would help distinguish one instance of the object from another. Movie clip objects, for example, have properties specific to movie clips, such as their number of frames ( _totalframes) and position ( _x and _ y).
Because object properties are named, not numbered, objects do not have any of the element-management tools of arrays (shift( ), unshift( ), push( ), splice( ), etc.). Object properties are traditionally set via methods of the object to preserve the encapsulated nature of an object. That is, in strict OOP, an object should set its own properties. If an outside entity wants to set an object's property, it should be done by calling an appropriate method of the object. For example, a purist would frown on setting the length property of an array directly. That purist would argue that it is best to let the Array object set the length property itself, and that code outside of the object should do so only indirectly, by calling one of the Array object's methods. In that case, the maintainer of the Array class could change the name of the length property to len without adversely affecting other users.
Copyright © 2002 O'Reilly & Associates. All rights reserved.