Defining Interfaces


As mentioned in the introduction to this chapter, classes have both an interface and an implementation. The interface is the way in which the outside world can communicate with an object. The interface simply says what methods are publicly available, what parameters those methods accept, and what, if any, types are returned by methods. The interface does not say anything at all about what a method does or how it does it. For example, the flash.net.LocalConnection and flash.net.NetConnection classes both define methods called connect() with identical signatures:

connect(value:String):void


However, notice that although that portion of the interface for both classes is identical, the actual implementations are quite different. LocalConnection objects listen for requests over a specified channel while NetConnection objects either make a connection to an RTMP server (if the parameter uses the RTMP protocol) or simply stores the parameter value for subsequent requests.

The class implementation is hidden from public view. When you call a method, you always call it by way of the interface, but the implementation is what runs. The implementation consists of the actual code that defines the internals of the method.

When you write code you can reference a class by typing variables and properties as the class. While that is not necessarily wrong, it does limit flexibility because it ties the code to a specific implementationthe concrete class. However, you can create more flexible code if you reference the interface instead. When you reference an interface rather than the implementation you don't lock the code into just one implementation. We'll talk more about this later in the chapter. For now what's important is to know that referencing interfaces rather than implementation is often a good strategy for creating flexible code, and we call this technique programming to interfaces.

When you program to an interface, you must write your classes so that they implement a formalized interface (more on what this means in a moment). This is essential for something called polymorphism, which we'll discuss shortly. To understand what a formal interface is, we can first look at what it is not. Just a moment ago, we mentioned that the LocalConnection and NetConnection classes have a common interface with the connect() method. However, that similarity is not part of a formalized interface. You can't declare a variable with an interface type that is generic enough to work for either LocalConnection or NetConnection. Rather, you must declare a variable as exactly LocalConnection or exactly NetConnection. This is an important distinction to make. Up to now we've said that all classes have both an interface and an implementation, and we've said that it's useful to be able to program to the interface rather than the implementation. However, unless we take steps to formalize an interface we cannot share that interface between more than class, which means we cannot polymorphically substitute one class for another in those cases. What we need to look at next is how to create a formal interface that is distinct from the implementation.

There are two ways to define formal interfaces: through inheritance and through explicit interface constructs. When you define an interface by either of these techniques, you can then define classes that implement the interface. This is an important concept that enables many of the design patterns discussed throughout this book. When you define a class that implements an interface, you can then declare variables of the interface type and assign to them instances of the implementing type. We'll be looking at this in much greater detail later in this chapter. First we'll look at how to define interfaces.

Interfaces Defined by Interface Constructs

ActionScript defines a formal interface construct that you can use to define interfaces. The syntax for defining an interface is very similar to that for defining a class, but it is simplified because it does not require (nor allow) you to provide any implementation. An interface construct defines only the interface. An interface consists of methods, including getters and setters. The basic syntax is as follows:

package package {    public interface Interface {       function method(parameter:Type):ReturnType;       function get property():ReturnType;       function set property(value:Type):void;    } }


The major differences between the syntax for a class and the syntax for an interface are that an interface uses the interface keyword rather than the class keyword and a semicolon appears after the return type for each method, instead of a code block defining the function body. Additionally, interfaces can describe only the public methods for implementing classes. That means that there is no need for a public/private/protected/internal modifier, and interfaces do not allow those modifiers.

Note

By convention, interface names start with I. For example IExample indicates that the type is an interface.


The following is an example of an interface called IExample:

package {    public interface IExample {       function sampleMethod(parameter1:String,               parameter2:uint):void;    } }


When you want to define a class that implements the interface, you use the implements keyword following the name of the class. For example, the following defines class A as implementing an interface called IExample:

public class A implements IExample {


If the class extends a superclass, then the implements keyword follows the name of the superclass:

public class A extends SuperClass implements IExample {


When a class implements an interface, it essentially signs a contract that it will implement the methods defined in the interface. If the implementing class does not define the necessary methods with exactly the same signatures as described in the interface, the compiler throws an error. For example, the following class says it implements IExample, but it does not declare the necessary method sampleMethod():

package {    public class A implements IExample {       public function A() {}    } }


Because A does not correctly define the necessary method, the compiler will throw an error. Also, if A is defined as follows, the compiler will still throw an error because although A defines sampleMethod(), it does not use the correct signature:

package {    public class A implements IExample {       public function A() {}       public function sampleMethod(parameter1:String):void {          trace("sampleMethod");       }    } }


The compiler will approve the class only when the class correctly adheres to the contract and defines all the necessary methods with the correct signatures, as it does in this example:

package {    public class A implements IExample {       public function A() {}       public function sampleMethod(parameter1:String,          parameter2:uint):void {          trace("sampleMethod");       }    } }


It's also important to note that, unlike inheritance, you can implement more than one interface per class. To implement more than one interface, simply use a comma-delimited list. For example, the following code defines A so that it implements IExample and ISample:

public class A implements IExample, ISample {


Note that a class signs a contract for each interface it implements. It must implement all the methods for all the interfaces it implements.

Interfaces Defined by Inheritance

As we've already discussed, the basic definition of an interface is the set of public methods (including getters and setter) for a class minus the actual implementation. All classes have interfaces (though by default the interfaces are tied together with the implementation), and if you define a subclass, it automatically inherits the interface of the superclass (as well as the superclass's implementation). This means that you can use inheritance to define interfaces.

Although all classes define interfaces (and can be used as interfaces), when we talk about explicitly defining interfaces using classes, we generally use a specific type of class called an abstract class. An abstract class is one that is not intended for instantiation. For example, if Example is an abstract class, you would never instantiate an Example object as follows:

var example:Example = new Example();


Rather, abstract classes are designed strictly to be subclassed and to define an interface that is shared among all the subclasses. Classes that subclass abstract classes and fill in their implementations are called concrete classes.

Abstract classes generally have little implementation. They defer the majority of implementation to subclasses. However, if you don't intend to add any implementation whatsoever, it is advisable that you use an interface construct as discussed in the previous section, "Interfaces Defined by Interface Constructs." Abstract classes in ActionScript 3.0 are typically most appropriate when you want to define a class that formalizes an interface for a set of subclasses, but also define a minimal amount of implementation.

Some programming languages define ways in which you declare abstract classes in an explicit fashion. When you define an abstract class with those languages, safeguards prevent you from accidentally instantiating an abstract class (generally, an exception is thrown). However, ActionScript 3.0 does not have a formal abstract class concept. Rather, the responsibility falls on the developer not to attempt to instantiate a class that is conceptually abstract.

There is nothing syntactically unique to abstract classes that sets them apart from standard classes. That is good news in that you don't have to learn anything new in terms of syntax.

When you want to define a class that implements the interface, you simply subclass the abstract class or a concrete class that extends the abstract class. Again, this technique of defining interfaces doesn't require any new syntax. You can simply use standard inheritance.

Deciding How to Define an Interface

How do you decide whether to define an interface through inheritance or through an interface construct? Generally you should always start with an interface construct. By using an interface construct you create the greatest degree of flexibility. If you then decide that you need an abstract class (because you want concrete classes to be able to inherit basic implementation) you should create an abstract class that implements the interface. This way you can always program to the interface construct, and if you later need to add more classes that implement the interface but don't inherit from the abstract class you can do that.




Advanced ActionScript 3 with Design Patterns
Advanced ActionScript 3 with Design Patterns
ISBN: 0321426568
EAN: 2147483647
Year: 2004
Pages: 132

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net