Flash Gordon
08-12-2007, 12:11 AM
Does anyone actually "program to interfaces over implementations"? I have never seen anyone do: var clip:Object = new MovieClip();. The authors of Design Patterns for Actionscript 3 by O'Reilly to give an explanation, but it looks like the most ridiculous thing I have ever seen.
So what does this principle of GoF really mean?
Below is a segment where they try to explain this:
1.8.2. Using Complex Interfaces
As you saw in Example 1-36, the program typed the instances to the implementation and
not the interfaces as was done in Example 1-20. This was caused by the key methods being
part of classes that implemented an interface and extended a class. Because of the way in
which the different display objects need to be employed, this dilemma will be a common
one in using Flash and ActionScript 3.0. Fortunately, a solution is at hand. (The solution
may be considered a workaround instead of the correct usage of the different structures
in ActionScript 3.0. However, with it, you can create methods that require some
DisplayObject structure and program to the interface instead of the implementation.)
If the interface includes a method to include a DisplayObject type, it can be an integral
part of the interface. Because Sprite is a subclass of the DisplayObject, its inclusion
in the interface lets you type to the interface when the class you instantiate is a subclass of
Sprite (or some other subclass of the DisplayObject, such as MovieClip.)
To see how this works, the application made up of Example 1-39 and Example 1-40 creates
a simple video player. The VidPlayer class builds the structural details of the video
playing operations. To do so requires that it subclass the Sprite class. By placing a getter
method with a DisplayObject type in the IVid interface, the application sets up a way
that the client can program to the interface.
package
{
import flash.display.DisplayObject;
public interface IVid
{
function playVid(flv:String):void;
function get displayObject():DisplayObject;
}
}
The implementation of the IVid interface includes a key element. The displayObject
() function is implemented to the DisplayObject class in building the VidPlayer
class.
package
{
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.display.Sprite;
import flash.display.DisplayObject;
public class VidPlayer extends Sprite implements IVid
{
private var ns:NetStream;
private var vid:Video;
private var nc:NetConnection;
public function get displayObject():DisplayObject
{
return this;
}
public function playVid(flv:String):void
{
nc=new NetConnection();
nc.connect(null);
ns=new NetStream(nc);
ns.play(flv);
vid=new Video();
vid.attachNetStream(ns);
addChild(vid);
}
}
}
Keep in mind that a getter method, using the get keyword, looks like a property, and is
treated like one. Any reference to displayObject is actually a method request. The trick
is to add the instance to the display list, and at the same time call the method that
establishes the instance as a DisplayObject. Example 1-41 does just that.
package
{
import flash.display.Sprite;
public class DoVid extends Sprite
{
//Type as Interface
private var showTime:IVid;
public function DoVid()
{
//Play the video
showTime=new VidPlayer();
showTime.playVid("iVid.flv");
//Include DisplayObject instance
addChild(showTime.displayObject);
showTime.displayObject.x=100;
showTime.displayObject.y=50;
}
}
}
In reviewing how the process works, first, the showTime instance is typed to the interface,
IVid. Next, showTime instantiates the VidPlayer class that has all the details for playing
the video. By doing so, it inherits the Sprite class as well as the IVid interface. Then the
showTime client plays the video using the playVid() method. Finally, when the
showTime instance is added to the display list with the addChild statement, it is added
as both the child of the VidPlayer class and the DisplayObject class by using the
displayObject getter. Because the getter, displayObject, is included in the display
list, you will not get the following error:
1067: Implicit coercion of a value of type IVid to an unrelated type flash.
display: DisplayObject.
IVid appears in the error because the instance was typed to the interface instead of the
implementation. By slipping in the DisplayObject typed getter method, we avoid the
error.
So what does this principle of GoF really mean?
Below is a segment where they try to explain this:
1.8.2. Using Complex Interfaces
As you saw in Example 1-36, the program typed the instances to the implementation and
not the interfaces as was done in Example 1-20. This was caused by the key methods being
part of classes that implemented an interface and extended a class. Because of the way in
which the different display objects need to be employed, this dilemma will be a common
one in using Flash and ActionScript 3.0. Fortunately, a solution is at hand. (The solution
may be considered a workaround instead of the correct usage of the different structures
in ActionScript 3.0. However, with it, you can create methods that require some
DisplayObject structure and program to the interface instead of the implementation.)
If the interface includes a method to include a DisplayObject type, it can be an integral
part of the interface. Because Sprite is a subclass of the DisplayObject, its inclusion
in the interface lets you type to the interface when the class you instantiate is a subclass of
Sprite (or some other subclass of the DisplayObject, such as MovieClip.)
To see how this works, the application made up of Example 1-39 and Example 1-40 creates
a simple video player. The VidPlayer class builds the structural details of the video
playing operations. To do so requires that it subclass the Sprite class. By placing a getter
method with a DisplayObject type in the IVid interface, the application sets up a way
that the client can program to the interface.
package
{
import flash.display.DisplayObject;
public interface IVid
{
function playVid(flv:String):void;
function get displayObject():DisplayObject;
}
}
The implementation of the IVid interface includes a key element. The displayObject
() function is implemented to the DisplayObject class in building the VidPlayer
class.
package
{
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.display.Sprite;
import flash.display.DisplayObject;
public class VidPlayer extends Sprite implements IVid
{
private var ns:NetStream;
private var vid:Video;
private var nc:NetConnection;
public function get displayObject():DisplayObject
{
return this;
}
public function playVid(flv:String):void
{
nc=new NetConnection();
nc.connect(null);
ns=new NetStream(nc);
ns.play(flv);
vid=new Video();
vid.attachNetStream(ns);
addChild(vid);
}
}
}
Keep in mind that a getter method, using the get keyword, looks like a property, and is
treated like one. Any reference to displayObject is actually a method request. The trick
is to add the instance to the display list, and at the same time call the method that
establishes the instance as a DisplayObject. Example 1-41 does just that.
package
{
import flash.display.Sprite;
public class DoVid extends Sprite
{
//Type as Interface
private var showTime:IVid;
public function DoVid()
{
//Play the video
showTime=new VidPlayer();
showTime.playVid("iVid.flv");
//Include DisplayObject instance
addChild(showTime.displayObject);
showTime.displayObject.x=100;
showTime.displayObject.y=50;
}
}
}
In reviewing how the process works, first, the showTime instance is typed to the interface,
IVid. Next, showTime instantiates the VidPlayer class that has all the details for playing
the video. By doing so, it inherits the Sprite class as well as the IVid interface. Then the
showTime client plays the video using the playVid() method. Finally, when the
showTime instance is added to the display list with the addChild statement, it is added
as both the child of the VidPlayer class and the DisplayObject class by using the
displayObject getter. Because the getter, displayObject, is included in the display
list, you will not get the following error:
1067: Implicit coercion of a value of type IVid to an unrelated type flash.
display: DisplayObject.
IVid appears in the error because the instance was typed to the interface instead of the
implementation. By slipping in the DisplayObject typed getter method, we avoid the
error.