AS3面向对象的概念:多态性(二)
实现接口
接口是使用ActionScript 3多态性的二种方法。不要与图形用户界面搞混了。接口是一种编程语言结构,用于创建的类实现特定的结构。在ActionScript 3,一个类可以实现多个接口。
//IAnimal.as package { public interface IAnimal { function getName():String; function eat():void; function talk():void; } }
首先我们可以看到的是,IAnimal接口声明了几个函数,这些功能与上述Animal抽象类的声明是相同的。只是接口中的函数缺少了public命名空间,以及括号构成的函数体。接口只允许声明公有的函数,你不能在接口中声明,静态或私有属性/方法。为什么不行呢?接口表现为一个契约,让外界对象知道在一个类中实现该接口有什么public公有方法可以访问。由于外部对象不能访问private私有方法,它们也不属于接口。若要实施良好封装,公有属性最好不要在接口中声明。一个类应该管理自己内部的状态,基于这个原因,你可以在接口在声明getters和setters属性,通过类的API访问这些属性。按照这个方法,类仍将维持自身的内部状态:
//this is perfectly valid in an interface function get myProperty():String; function set myProperty(v:String):void;
下面的类实现IAnimal接口。请注意,他们没有扩展任何类。此外,实现接口没有必要使用override覆盖语法。他们没有父类,也没有方法需要覆盖。
//Mouse.as package { public class Mouse implements IAnimal { public function Mouse() { } public function getName():String { return "Mouse"; } public function eat():void { trace("nom nom nom cheese"); } public function talk():void { trace("squeek squeek"); } } } //Pig.as package { public class Pig implements IAnimal { public function Pig() { } public function getName():String { return "Pig"; } public function eat():void { trace("nom nom nom poo"); } public function talk():void { trace("oink oink"); } } } //Polymorphism.as package { import flash.display.Sprite; public class Polymorphism extends Sprite { protected var menagerie:Array = []; public function Polymorphism() { //create some animals that implement IAnimal var pig:IAnimal = new Pig(); var mouse:IAnimal = new Mouse(); menagerie = [ pig, mouse ]; //make the IAnimal instances perform for each(var animal:IAnimal in menagerie) { //animal does its thing trace(animal.getName() + " implements IAnimal") animal.eat(); animal.talk(); trace("----"); } } } }
你可以从第二个例子看到结果非常相似。在循环中每个IAnima共有一个接口,允许我们访问接口的方法,类的具体实现反而并不重要。
Pig implements IAnimal nom nom nom poo oink oink ---- Mouse implements IAnimal nom nom nom cheese squeek squeek ----
接口和类继承决不是相互排斥的概念。一个类可以从父类扩展,也可以有一个或多个接口。
//Horse.as package { public class Horse extends Animal implements IAnimal { public function Horse() { super("Horse"); } override public function getName():String { return name; } override public function eat():void { trace("nom nom nom hay"); } override public function talk():void { trace("nayyyy nayyyy"); } } }
Horse类从Animal扩展并实现IAnimal接口。
接口在实践中的应用
上面的例子显然不大有用,除非你模拟农场或动物园。我经常在我们应用程序中使用这些概念。
Services——服务,例如,我最近创建了IImageService接口,由FlickrImageService、 FacebookImageService和 XMLImageService类实现该接口,这些服务实现共同的接口,允许创建一个应用程序配置,他并不关心图像来自哪里。
DataTypes——在Flex框架在随处可见。ArrayCollection 和其它一些集合类实现ICollectionView,它允许你使用实现了ICollectionView接口的类作为Flex许多组件的提供者。
Event Responders——IResponder是Flex框架中的一个接口,使用频率很高。类实现该接口可异步响应远程方法。
Containers——IContainer是Flex框架接口,定义了一个类可以作为一个可视容器。
铭记代码采用接口这种方法,可让你提高类的重用性。将来开发者能够以接口契约替代新的实现,极大地开拓了扩展的可能性。当我们依着接口编码,到时应用程序中的单元测试会非常容易。在测试中服务,数据类和其它实现用模拟对象可以轻易地被替代。