An ActionScript 2.0 Primer for ActionScript 1.0 Folk: Part Three

by Joey Lott (www.person13.com)

In parts two of this series I introduced you to the ActionScript 2.0 class structure and syntax. We looked at the basics of creating an ActionScript 2.0 class including using packages, public/private/static class members, getter and setter methods, and so forth. But two of the things that we didn’t talk about were inheritance and interfaces. In this third part I’ll discuss each of these topics in more detail.
Understanding Inheritance
Inheritance is not new to ActionScript 2.0 classes as a concept, but it may be a somewhat unfamiliar topic to some. And as such, it bears a little introductory explanation.
Inheritance refers to hierarchical relationships that can exist between classes. Classes can be defined such that they are a subclass of a superclass, meaning that the subclass automatically inherits all the members of the superclass without having to explicitly redefine them. This is a very important and beneficial feature with regard to classes because it allows for greater levels of abstraction. And greater levels of abstraction mean you get to have much more efficient workflow.
Here’s an example to help you understand how inheritance is beneficial: Let’s say you want to create a Car class similar to the class you created in part two of this series of articles. Now clearly a Car is one of many types of vehicles including Boat, Train, Plane, etc. While all of the vehicles are sufficiently different that they each warrant their own class, they also share some common characteristics. All of the aforementioned vehicles could have properties indicating the passenger capacity and the number of miles it has traveled. In addition, each vehicle is capable of moving, and as such, you could create a method that would move the vehicle at a given rate of speed.
If you create a superclass such as Vehicle, that contains all the common characteristics and functionality of the classes such as Car, Boat, Train, and Plane, then you only have to define that common code in one place rather than repeating it in each class. Creating a superclass does not require any special techniques. You create the class just as with any class you have written up to now. The additional techniques required in setting up inheritance are all within the subclasses.
Extending a Superclass
To create a subclass you must tell Flash what class you want to use as the superclass. In ActionScript OO (Object-Oriented) terminology we say that a subclass extends a superclass. In the case of our example we want a class such as Car to extend the superclass Vehicle. In order to tell Flash to create this hierarchical relationship just use the extends keyword in the subclass declaration as follows:
class Subclass extends Superclass {
}

So in the case of the Car and Vehicle example the basic Car class declaration would look like this:
class Car extends Vehicle {
}

Once you’ve defined the Car class to extend the Vehicle class, then all the properties and method of the Vehicle class are automatically accessible within the Car class.
Calling and Overriding Superclass Methods
Often times you’ll want a subclass to inherit a superclass’s method exactly as they are implemented within the superclass. In such cases you don’t need to do anything within the subclass defintion with respect to those methods. But in other cases you will want to define a specialized implementation of one of those methods within the subclass. We call this overriding a method because the subclass defines its own implementation which effectively overrides the inherited version.
When you override a method you have several options:
* You can override the method completely such that the superclass method’s implementation is disregarded altogether.
* You can override the method such that the superclass’s method is still called, but the subclass implementation adds some additional functionality.
In order to completely override a superclass method all you need to do is define a method with the same name in the subclass in which there are no references to the superclass method. For example, if the superclass has a method such as:

// Method defined in the superclass. 
public function display():Void {
trace("This is the superclass method.");
}


Then you could define a subclass implementation of the method that disregards the superclass method with the following:

// Method defined in the subclass.
public function display():Void {
  trace("This is the subclass method.");
} 


However, any time you want to create a subclass implementation of a method that also calls the superclass implementation, you can use the super keyword to reference the superclass and explicitly call the superclass’s method from within the subclass implementation. For example, the display() method example in the subclass could be rewritten as follows so that it also calls the superclass’s implementation:

// Method defined in the subclass that also calls the superclass method. 
public function display():Void {
super.display();
trace("This is the subclass method.");
}


When the display() method is calls from an instance of the subclass it will display the following in the Output panel:

This is the superclass method. 
This is the subclass method.


You can use the super reference at any point within the subclass. For example, if you call super(), then it references the constructor method of the superclass. This is useful when you want the subclass constructor to perform some actions unique to the subclass, but you also want to call the superclass constructor with some particular values passed to it. The only caveat is that the superclass constructor must always be called on the first line within the subclass constructor if you explicitly call it. Otherwise you will get a compilation error.
Creating a Vehicle and Car class
You’ve had a chance to read some of the theory. Now let’s apply that theory in a simple exercise. In this example you’ll have the chance to create a Vehicle class and a Car subclass. If you completed the exercise from part two of this series of articles, then you’ll have a pretty easy time following along with the functionality in this exercise. If you didn’t complete the exercise from part two and you find that you feel a little confused about the functionality in this example, you might want to go and review that previous example from part two.
1. If you didn’t already do so, create a package directory structure for the package com.person13 within a directory in your Flash classpath. For example, if D:\ActionScriptClasses is in your Flash classpath, create D:\ActionScriptClasses\com\person13.
2. Open a new ActionScript file.
3. Add the following code to the file:

class com.person13.Vehicle { 
private var _nPassengers:Number;
private var _nMiles:Number;
private var _nInterval:Number;
function Vehicle(nPassengers:Number, nMiles:Number) {
_nPassengers = nPassengers;
miles = nMiles;
}
public function get passengers():Number {
return _nPassengers;
}
public function get miles():Number {
return _nMiles;
}
public function set miles(nMiles:Number):Void { if(nMiles >= 0) {
_nMiles = nMiles;
}
else {
_nMiles = 0;
}
}
public function move(nMPH:Number):Void {
if(nMPH == null || nMPH <= 0) {
clearInterval(_nInterval);
}
else {
_nInterval = setInterval(this, "increment", 1000, nMPH);
}
}
private function increment(nMPH:Number):Void {
_nMiles += nMPH;
}
}


4. Save the file as Vehicle.as to the com/person13 directory.
5. If you completed the exercise in part two of this series of articles, then open the Car.as file you created previously (should already exist in the com/person13 directory). Otherwise, open a new ActionScript file.
6. Modify the code or add the following code to the file:

// The Car class extends Vehicle so it will inherit all the properties
// and methods of the superclass. 
class com.person13.Car extends com.person13.Vehicle{
// Declare the properties that are specific to Car. The other properties // are inherited, and you don't need to redeclare them.
private var _sMake:String;
private var _sModel:String;
private var _nYear:Number;
function Car(sMake:String, sModel:String, nYear:Number, nPassengers:Number, nMiles:Number) {
// Call the superclass constructor, then assign the values for the
// Car-specific properties.
super(nPassengers, nMiles);
_sMake = sMake;
_sModel = sModel;
year = nYear;
}
public function get make():String {
return _sMake;
}
public function get model():String {
return _sModel;
}
public function get year():Number {
return _nYear;
}
public function set year(nYear:Number):Void {
if(nYear >= 1886) {
_nYear = nYear;
}
else {
_nYear = 1886;
}
}
// Define a method called drive() that just calls the move() method
// that it inherits from Vehicle. This is not necessary, but it just
// means that you can declare a more intuitive API for the Car class
// since the term drive is more specifically related to cars than
// the generic term move.
public function drive(nMPH:Number):Void {
move(nMPH);
}
}


7. Save the file in the same com/person13 directory to which you saved Vehicle.as. If the file is new (as in you aren’t modifying the Car.as file from the exercise from part two) then name the file Car.as. Otherwise, the file should already be named Car.as.
8. If you completed the exercise from part two then open the same .fla you used to test that example. Otherwise create a new .fla.
9. If you already completed the .fla for the previous exercise then you don’t need to modify the code. If you are creating a new .fla, then add the following code to the first frame of the default layer:

import com.person13.*; 
function displayMileage(carObj:Car):Void {
trace(carObj.miles);
}
var car:Car = new Car("Oldsmobile", "Alero", 2000, 5, 43000);
car.drive(65);
setInterval(displayMileage, 100, car);


10. Test the movie. You should see the miles value continually displayed in the Output panel, incrementing approximately every second.
[Optional]
11. Open a new ActionScript file.
12. Add the following code in the file:

class com.person13.Plane extends com.person13.Vehicle{ 
private var _sMake:String;
private var _sModel:String;
function Plane(sMake:String, sModel:String, nPassengers:Number, nMiles:Number) {
super(nPassengers, nMiles);
_sMake = sMake;
_sModel = sModel;
}
public function get make():String {
return _sMake;
}
public function get model():String {
return _sModel;
} public function fly(nMPH:Number):Void {
move(nMPH);
}
}


13. Save the file as Plane.as in the com/person13 directory.
14. Open a new .fla.
15. Add the following code to the first frame of the default layer:

import com.person13.*; 
function displayMileage(obj:Plane):Void {
trace(obj.miles);
}
var plane:Plane = new Plane("Boeing", "747", 300, 100000);
plane.fly(400);
setInterval(displayMileage, 100, plane);


16. Test the movie.
Extending Subclasses
You are not limited to creating only one level of inheritance. You can also extend a subclass…or a subclass of a subclass for that matter. For example, you could create a Ferrari class that extends Car or a Lear class that extends Plane. The process is the same when extending any class regardless of whether the superclass happens to be a subclass of another class or not.
Understanding Interfaces
Interfaces are probably one of the least understood programming concepts. Interfaces are quite simply a set of rules with which classes can be in accordance. When you define a class to agree to the rules of an interface we say that the class implements the interface.
So what types of rules or guidelines does an interface define? In specific terms, an ActionScript 2.0 interface tells Flash what methods a class must implement including the following information
* the name of the method
* what parameters it should expect
* the public declaration of the method (you cannot declare private or static methods in an interface)
* the return type

An interface may not contain any of the following:
* property declarations
* method implementations
* private or static method declarations

A class can then implement an interface. When the class implements an interface it agrees to have, perhaps among other things, methods that match the methods declared in the interface. If it does not contain the matching methods then Flash will generate an error when you try to compile.
Benefits of Interfaces
Often developers do not initially understand the potential benefits of interfaces. After all, what is there to be gained by using interfaces? At first it would seem that you go to an extra effort with no substantial payback. An interface does not provide any functionality because it does not actually implement any of the methods it declares.
The real advantages of interfaces are somewhat subtle and in order to seem them you have to take a step back and look at the bigger picture. If you are creating a single class for a single application then there is really no point whatsoever in writing an interface for the class. And not every class should necessarily implement an interface. But when you are working within a larger scope – larger timeframes, larger projects, larger teams – then interfaces help you to create basic blueprints that can improve workflow not only when developing classes, but also when utilizing the classes.
For example, let’s say you’re working on a team to create a group of classes such as Vehicle, Animal, Wind, and Planet. While each of these classes is likely to have varying APIs, they might all share one thing in common – they can all move. If moving is something that you want to implement in each of the classes, you might want to create an IMoveable interface that all of the classes can implement. The IMoveable interface would declare the move() method such that each implementing class would agree to then have a move() method. This is helpful for the team. When you create the interface and determine which classes will implement it, then the developer working on the class already knows what methods to write, and it provides standardization across the class APIs. The other benefit is for the developer who is utilizing a class. If you, as a developer using a class, happen to know that the class implements a particular interface, then you already know something about its API.
A class can implement multiple interfaces. And for that reason interfaces are often utilized as a form of multiple inheritance in languages that don’t support actual multiple inheritance. In ActionScript a class can only extend one other class. For example, the Car class extends Vehicle, and therefore it cannot extend any other classes. But Car can implement multiple interfaces (at the same time as it extends Vehicle.) For example, Car could implement interfaces such as IDrivable, IManufacturable, ISellable.
Creating an Interface
You’ve read the theory. Now let’s look at declaring and defining an interface. Since you already know the syntax and structure for classes, you’re not going to learn too much that is new.
The interface declaration looks almost identical to the class declaration. The only difference is that an interface declaration uses the interface keyword instead of the class keyword. For example:

interface IMoveable { 
// Interface definition.
}


An interface can only specify which methods an implementing class must have. So you will not be declaring any properties within your interfaces. And you should not define/implement any of the methods within the interface. Each of the method declarations should consist of only the following elements (this is reiterated from previous):
* the name of the method
* what parameters it should expect
* the public declaration of the method
* the return type

Here’s an example of a complete IMoveable interface:

interface IMoveable { 
public function move(nMPH:Number):Void;
}


Just as with classes, you can package interfaces. For example, if you want to package IMoveable in the com.person13 package you can declare it as follows:

interface com.person13.IMoveable { 
public function move(nMPH:Number):Void;
}


And you can also extend interfaces just like classes. So, for example, if you wanted to create a IDrivable interface to extend IMoveable, it might look something like the following:

import com.person13.IMoveable 
interface com.person13.IDrivable extends IMoveable {
public function drive(nMPH:Number):Void;
}


Implementing an Interface
Once you’ve defined an interface you can tell a class you want it to implement the interface using the implements keyword followed by a comma-delimited list of the interfaces you want it to implement. For example, if you want the Vehicle class to implement the IMoveable interface the beginning of the class declaration might look like:

class com.person13.Vehicle implements com.person13.IMoveable { 


Or, of course, you could use an import statement to first import the interface:

import com.person13.IMoveable; 
class com.person13.Vehicle implements IMoveable {


In the hypothetical scenario in which the Car class implements multiple interfaces such as IDrivable, IManufacturable, and ISellable, the first part of the class declaration might look like:

import com.person13.*; 
class com.person13.Car implements IDrivable, IManufacturable, ISellable {


When a class implements an interface, Flash will check during compile time to ensure that the class has all the correct implementations. If a method is missing or incorrectly declared in the class so as to not adhere to the interface, Flash will display an error message letting you know.
Conclusion
That wraps up the third article in this series. Let me know if you have any questions or comments about anything that has been covered. Keep an eye out for another installment. Next I’ll talk about error handling using try-catch-finally and throw – yet another new feature in ActionScript 2.0.
As always, thank you.


评论

该日志第一篇评论

发表评论

评论也有版权!