View comments | RSS feed

Interfaces

An interface is a collection of method declarations that allows unrelated objects to communicate with one another. For example, the Flash Player API defines the IEventDispatcher interface, which contains method declarations that a class can use to handle event objects. The IEventDispatcher interface establishes a standard way for objects to pass event objects to one another. The following code shows the definition of the IEventDispatcher interface:

public interface IEventDispatcher
{
    function addEventListener(type:String, listener:Function, 
            useCapture:Boolean=false, priority:int=0,
            useWeakReference:Boolean = false):void;
    function removeEventListener(type:String, listener:Function, 
            useCapture:Boolean=false):void;
    function dispatchEvent(event:Event):Boolean;
    function hasEventListener(type:String):Boolean;
    function willTrigger(type:String):Boolean;
}

Interfaces are based on the distinction between a method's interface and its implementation. A method's interface includes all the information necessary to invoke that method, including the name of the method, all of its parameters, and its return type. A method's implementation includes not only the interface information, but also the executable statements that carry out the method's behavior. An interface definition contains only method interfaces, and any class that implements the interface is responsible for defining the method implementations.

In the Flash Player API, the EventDispatcher class implements the IEventDispatcher interface by defining all of the IEventDispatcher interface methods and adding method bodies to each of the methods. The following code is an excerpt from the EventDispatcher class definition:

public class EventDispatcher implements IEventDispatcher
{
    function dispatchEvent(event:Event):Boolean
    {
        /* implementation statements */
    }

    ...
}

The IEventDispatcher interface serves as a protocol that EventDispatcher instances use to process event objects and pass them to other objects that have also implemented the IEventDispatcher interface.

Another way to describe an interface is to say that it defines a data type just as a class does. Accordingly, an interface can be used as a type annotation, just as a class can. As a data type, an interface can also be used with operators, such as the is and as operators, that require a data type. Unlike a class, however, an interface cannot be instantiated. This distinction has led many programmers to think of interfaces as abstract data types and classes as concrete data types.

Subtopics

Defining an interface
Implementing an interface in a class

Defining an interface

The structure of an interface definition is similar to that of a class definition, except that an interface can contain only methods with no method bodies. Interfaces cannot include variables or constants but can include getters and setters. To define an interface, use the interface keyword. For example, the following interface, IExternalizable, is part of the flash.utils package in the Flash Player API. The IExternalizable interface defines a protocol for serializing an object, which means converting an object into a format suitable for storage on a device or for transport across a network.

public interface IExternalizable
{
    function writeExternal(output:IDataOutput):void;
    function readExternal(input:IDataInput):void;
}

Note that the IExternalizable interface is declared with the public access control modifier. Interface definitions may only be modified by the public and internal access control specifiers. The method declarations inside an interface definition cannot have any access control specifiers.

The Flash Player API follows a convention in which interface names begin with an uppercase I, but you can use any legal identifier as an interface name. Interface definitions are often placed at the top level of a package. Interface definitions cannot be placed inside a class definition or inside another interface definition.

Interfaces can extend one or more other interfaces. For example, the following interface, IExample, extends the IExternalizable interface:

public interface IExample extends IExternalizable
{
    function extra():void;
}

Any class that implements the IExample interface must include implementations not only for the extra() method, but also for the writeExternal() and readExternal() methods inherited from the IExternalizable interface.

Implementing an interface in a class

A class is the only ActionScript 3.0 language element that can implement an interface. Use the implements keyword in a class declaration to implement one or more interfaces. The following example defines two interfaces, IAlpha and IBeta, and a class, Alpha, that implements them both:

interface IAlpha
{
    function foo(str:String):String;
}

interface IBeta
{
    function bar():void;
}

class Alpha implements IAlpha, IBeta
{
    public function foo(param:String):String {}
    public function bar():void {}
}

In a class that implements an interface, implemented methods must do the following:

You do have some flexibility, however, in how you name the parameters of methods that you implement. Although the number of parameters and the data type of each parameter in the implemented method must match that of the interface method, the parameter names do not need to match. For example, in the previous example the parameter of the Alpha.foo() method is named param:

public function foo(param:String):String {}

But the parameter is named str in the IAlpha.foo() interface method:

function foo(str:String):String;

You also have some flexibility with default parameter values. An interface definition can include function declarations with default parameter values. A method that implements such a function declaration must have a default parameter value that is a member of the same data type as the value specified in the interface definition, but the actual value does not have to match. For example, the following code defines an interface that contains a method with a default parameter value of 3:

interface IGamma
{
    function doSomething(param:int = 3):void;
}

The following class definition implements the Igamma interface but uses a different default parameter value:

class Gamma implements IGamma
{
    public function doSomething(param:int = 4):void {}
}

The reason for this flexibility is that the rules for implementing an interface are designed specifically to ensure data type compatibility, and requiring identical parameter names and default parameter values is not necessary to achieve that objective.


Flash CS3


Comments


petkusj said on Nov 13, 2007 at 5:29 PM :
What's the purpose behind the interface? All it really seems to do is keep
me one step removed from manipulating the properties of a class. I
understand that a class can implement more than one interface and
several classes can implement the same interface and I guess I see how
that might be useful, but most of the interface names I've seen appear to
be pretty specific: IEventDispatcher seems inextricably linked to
EventDispatcher and ICellRenderer to CellRenderer. Does Flash compile
faster because an interface was created? It certainly doesn't seem any
easier to use.

Am I correct in thinking that an interface only makes sense when it is used
by more than one class? That it would be pointless to make an interface
for only one class?

Jennifer
adbe_paul said on Nov 14, 2007 at 4:49 PM :
@petkusj (Jennifer)

You're absolutely right that an interface only makes sense when it's used by more than one class. Specifically, an interface is useful when you're writing code that other developers are going to be using, or that you will be using in a future time for a purpose that you might not be able to anticipate. The idea behind using an interface is to make the code flexible.

Often, as you've noted, a library of code (such as the ActionScript core classes) includes an interface, and also includes one class that implements the interface (often referred to as the "default" implementation). The idea is that for most needs, the default implementation will be sufficient/useable, but in case it's not a developer can create their own class that implements the interface, and can still use it in place of the default implementation.

For a concrete example, consider the IEventDispatcher interface and the EventDispatcher class. Every class that will be part of the ActionScript 3.0 event model must implement the IEventDispatcher interface, because there are places in ActionScript where IEventDispatcher is used as the data type of a property or a method parameter, and objects that dispatch events must be able to be used in those cases. In the vast majority of cases, if you want to create a class that will dispatch events, you can make that class a subclass of EventDispatcher, and the class inherits all the functionality it needs for dispatching events.

What happens, however, if you are creating a class that will dispatch events (we'll call it "MyClass") and you *also* need the class to expose some other functionality that's part of a different (non-EventDispatcher) class; for instance, imagine you need to be able to assign MyClass instances to a property whose data type is a non-EventDispatcher class (e.g. MyNonEventClass). In that case, in order to assign MyClass instances to that property, MyClass would have to be a MyNonEventClass subclass.

In that case, if there was no IEventDispatcher interface and only an EventDispatcher class, you would have to choose to either 1) not use the built-in event handling mechanisms for the class, or 2) not be able to make the class a MyNonEventClass subclass (and hence wouldn't be able to use it for it's intended purpose).

As it is, however, you could make MyClass be a MyNonEventClass subclass, *and* implement the IEventDispatcher interface, and by doing so you can use the class in both situations (in the built-in event handling framework, and in the places where you need a MyNonEventClass instance).

As I said, in the vast majority of cases you'd just make your class an EventDispatcher subclass, and that's all that you need. But in those cases where you can't, it's sure handy to have that IEventDispatcher interface. (For a real-world example, once I was creating a flash.utils.Proxy subclass, but I wanted to be able to dispatch events as well. Since Proxy isn't an EventDispatcher subclass, I had to implement IEventDispatcher.)

Sorry this is so long, and hopefully it is helpful.
petkusj said on Nov 15, 2007 at 9:51 AM :
Thanks, adbe_paul. When you say:

In that case, if there was no IEventDispatcher interface and only an
EventDispatcher class, you would have to choose to either 1) not use the
built-in event handling mechanisms for the class, or 2) not be able to make
the class a MyNonEventClass subclass (and hence wouldn't be able to use
it for it's intended purpose).

You're kind of saying I get to eat my cake and have it too.

It seems to me, however, that for most of the programming I will be doing, I
probably won't need to create interfaces. But I may often be extending or
implementing interfaces. In your example, it seems I would be both
extending AND implementing an interface?

Jennifer

PS I think I answered my own question.
adbe_paul said on Nov 15, 2007 at 3:09 PM :
@petkusj:

Yes, for most of the programming that most people will be doing, you won't need to create interfaces. The most common case where you'd create an interface is if you're creating a class library or framework that is designed for other developers to use. Another common use of interfaces is if you're using what are called "design patterns" -- which are essentially strategies for structuring applications to solve specific programming problems.

And yes, it'll be more common for you to be extending classes and/or implementing interfaces...and if you're writing a class that implements an interface, there's a good chance that in that class you're also extending another class (as in the example I gave).

The good news is that, if the library/framework is designed well, you can often make use of the default implementation (if there is one) to help you implement the interface. For instance, if I'm writing a class that implements IEventDispatcher because I can't extend EventDispatcher, I can still create and use an EventDispatcher internally in my class as a "helper", so that I don't have to recreate the functionality that's already built into EventDispatcher. Here's a minimal example of an IEventDispatcher that uses EventDispatcher internally to do its work (a common way to say this is that you "incorporate the class using 'composition' rather than 'inheritance'"). It definitely requires more code than just extending EventDispatcher, but the good news is that the code can be identical for any IEventDispatcher that includes an EventDispatcher by composition, and as you can see all the work is really done by the EventDispatcher instance that's included in the class:

package
{
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;

public class MyClass extends MyNonEventClass implements IEventDispatcher
{
//
// IEventDispatcher implementation
//
private var _eventDispatcher:EventDispatcher;

public function MyClass()
{
_eventDispatcher = new EventDispatcher(this);
}

public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
{
_eventDispatcher.addEventListener(type, listener, useCapture, priority);
}

public function dispatchEvent(event:Event):Boolean
{
return _eventDispatcher.dispatchEvent(event);
}

public function hasEventListener(type:String):Boolean
{
return _eventDispatcher.hasEventListener(type);
}

public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
{
_eventDispatcher.removeEventListener(type, listener, useCapture);
}

public function willTrigger(type:String):Boolean
{
return _eventDispatcher.willTrigger(type);
}
}
}
bobw2829 said on Jan 11, 2008 at 10:52 AM :
Also, correct me if I'm wrong, interfaces can be intregal in downcasting - which is comparing two different object types that share the same interface. For example, if you have object type foo and object type bar, and if they both implement the same Interface, you can compare the two objects.

 

RSS feed | Send me an e-mail when comments are added to this page | Comment Report

Current page: http://livedocs.adobe.com/flash/9.0/main/00000067.html