As3.0 Interface 与类的使用

本文详细介绍了AS3中的抽象类与接口的概念及其应用。包括抽象类的特点、如何使用抽象方法,以及接口的设计原则和与抽象类的区别。此外,还讨论了它们在软件设计中的作用及适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来源:http://blog.sina.com.cn/s/blog_4d65c19e0100bfkb.html

抽象类:又叫抽象基类:可以包含一般类所包含的所有特性,例如,字段,属性,方法,抽象类不能被实例化他主要用在类的定义和部分实现这方面,所以他需要在扩充类中完整的扩充并实现功能.另外抽象类还包含一个很特殊的方法,叫抽象方法(这些方法基本上是没有执行代码的函数,由继承于该类的类重写(override)并提供具体实现).在Java和C#中,有abstract关键字来定义抽象类,而在As3中,并没有提供抽象类的支持,尽管abstract已经属于关键字,我们只可以通过模拟方法来实现抽象类的机制。在AS3笔记(11),适配器模式(Adapter Pattern)的范例中,Adaptee.as就是一个抽象类,而如requestB()则是一个抽象方法.

 


package {
    public class Adaptee {
        public function requestA():void {
            trace("Adaptee:requestA()");
        }
        public function requestB() {

        }
        public function requestC():void {
            trace("Adaptee:requestC()");
        }
    }
}

 

接口:接口是一种特殊的抽象类,用interface 关键字标记,他可以包含实例/静态方法和getter/setter方法,任何实现该接口的类就必须按照接口的定义实现这些方法.As3中的类可以实现(implements)多个接口.相对于类,接口更象是一种方法的协议,使用接口可以更好的管理模块的功能,方便整理和引用。在AS3笔记(11),适配器模式(Adapter Pattern)的范例中,ITarget.as则是一个典型的接口.

 


package {
    public interface ITarget {
        function renamedRequestA():void;
        function requestA():void;
        function requestB():void;
        function requestC():void;
        function requestD():void;
    }
}


帮助中提到,接口是定义一个方法组的数据类型,其中的方法必须由实现接口的任何类定义。

 

接口与类相似,但也有以下重要差异:

  • 接口仅包含方法的声明,而不包含其实现。也就是说,实现接口的每个类必须为该接口中声明的每个方法提供实现。
  • 接口方法定义无法具有任何属性,例如 public 或 private,但是在实现接口的类的定义中,实现的方法必须标记为 public
  • 多个接口可以通过 extends 语句由接口继承,或通过 implements 语句由类继承。


从编程的角度来看,抽象类和接口都可以用来实现"design by contract"的思想。
在具体的使用上,抽象类表示的是一种继承关系,在AS3中,只支持单继承不支持多继承。但是,一个类却可以实现多个接口。这和Java一样。

其次,在抽象类的定义中,我们可以赋予方法的默认方法。但是在接口的定义中,方法却不能拥有默认行为。不能定义默认方法,对于后期代码的维护相对比较麻烦,比如需要给所有实现接口的类修改默认方法,可能需要修改每一个类,而如果是继承,则只需要修改抽象类即可。虽然我们可以通过委托来绕过定义默认行为,但是仍然有一点麻烦。

从程序设计的角度来看,接口很大程度上可以弥补无法使用多继承而带来的问题。见下图
图1
AS3 <wbr>interface的笔记 <wbr>(续)——抽象类和接口
图1为一个典型的继承案例.例子中为生成一个bus driver实例类和一个taxi driver实例类.

图2

AS3 <wbr>interface的笔记 <wbr>(续)——抽象类和接口
由于没有多继承,我们要生成一个男公车司机和女出租车司机看起来都不那么靠谱.那怎么办呢?一般除了让其中的一类做为功能复合到最后的实例类中,更标准的就是使用接口了.见下图:
图3
AS3 <wbr>interface的笔记 <wbr>(续)——抽象类和接口
图3表示继承自man和woman的实例类bus driver和taxi driver实现了通过employment接口标准的dirver类功能。综合来说,抽象类的应用一般为树性结构,而加入接口的应用可以使结构更丰富可靠。
总结一下抽象类和接口在语法和设计原则上的区别   
    
  1.抽象类是对对象的抽象,可以把抽象类理解为把类当作对象,抽象成的类叫做抽象类。
    接口只是一个行为的规范或规定,抽象类更多是定义在一系列紧密相关的类间,而接口大多数是关系疏松但都实现某一功能的类种。
  2.一个类一次可以实现若干个接口,但是只能扩展一个父类。
  3.默认情况下,ActionScript 3.0 中的所有类都是密封的,所以抽象类也能被密封。
  4.接口与非抽象类类似,抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是,允许抽象类将接口方法映射到抽象方法上。
  5.抽象类实现了oop中的一个原则,把可变的与不可变的分离。抽象类和接口就是定义为不可变的,而把可变的作为子类去实现。
  6.  好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。   
  7.尽量避免使用继承来实现组建功能,而是使用黑箱复用,即对象组合。因为继承的层次增多,造成最直接的后果就是当你调用这个类群中某一类,就必须把他们全部加载到内存中,非常耗资源。   
  8.如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中的方法。

应用场景:
如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单的方法来控制组件版本。
如果创建的功能将在大范围的全异象间使用,则使用接口。
如果要设计小而简练的功能块,则使用接口。
如果要设计大的功能单元,则使用抽象类。
要在组件的所有实现间提供通用的已实现功能,则使用抽象类。

关于As3的抽象类与接口,还可以看一下几篇文章:
http://www.asv5.cn/blog/article.asp?id=164
http://riaidea.com/article.asp?id=26
http://space.actionscript3.cn/html/73/t-973.html

转载于:https://www.cnblogs.com/-yan/p/4423277.html

一个就是使用继承。比方说,你可以先创建一个颜色处理器的。 package{ public class colorProcessor{ public function setFillColor(color:uint):void{ } } } 然后,形状和文本就可以继承colorProcessor了。 package{ public class shapeClass extends colorProcessor{ override public function setFillColor(color:uint):void{ //.... } //由于还可以设置线条,你可以在这里新加一个方法 public function setLineColor(color:uint):void{ //.... } } } package{ public class textClass extends colorProcessor{ override public function setFillColor(color:uint):void{ //.... } } } 因为对文本和对形状的填充颜色设置可能会采用不同的实现方法,比方说,中国人吃饭和外国人吃饭都是吃饭,但是中国人可能用筷子,外国人则用刀叉。所以,在colorProcessor里,setFillColor就没有包含方法的实现了,给被继承的自我扩充。 第二种方法,使用接口。把colorProcessor写成接口。 package{ public interface IColorProcessor{ functon setFillColor(color:uint):void } } 然后形状和文本则改成 package{ public class shapeClass implements IColorProcessor{ public function setFillColor(color:uint):void{ //.... } //由于还可以设置线条,你可以在这里新加一个方法 public function setLineColor(color:uint):void{ //.... } } } package{ public class textClass implements IColorProcessor{ public function setFillColor(color:uint):void{ //.... } } } 这 么看起来,colorProcessor和IColorProcessor接口没有太大区别。这两个都声明了方法,也没有包含方法的实现。使用继承父 的,则通过覆盖方法来实现被继承的方法,而实现接口的则在接口实现的里写出了方法的实现。像colorProcessor里这种只声明方法,里面实际 上没有方法实现的,实际上是运用了抽象的思想。不过,在AS3里尚不可自定义抽象,所以,所谓的抽象也只是有形无实。真正的抽象跟接口一样,不 能实例化,而且,继承者必须覆盖抽象的所有方法才可以实例化(所以这点跟接口也很相似)。AS3有内置的抽象如 DisplayObjectContainer,大家可以尝试去用来测试实例化,继承的可行性。 说到这里,其实还是没有说明接口存在的必要性。显 然,上面的形状和文本,即使没有“抽象”和接口,两个照样可以正常运行。但是,假若现在加入了MC,MC不具备设置颜色的属性,那么,在Flash 的IDE下,你使用颜料桶工具将无法对MC进行颜色填充,如果你要开发一个Flash的IDE,那么,你就将要对你选中的对象进行判断,它是文本,形状, 还是MC。 在AS3里,对象型有关的运算主要有以下几种: getQualifiedClassName getQualifiedSuperclassName is instanceof(还是推荐用is代替) as getQuailiedClassName可以获取该对象的型,返回的是名。假若my_txt是文本,my_shape是形状,那么,就有 getQualifiedClassName(my_txt)将返回textClass getQualifiedClassName(my_shape)将返回shapeClass 那么,在仅有这三种对象存在,并且该三种对象没有扩展的时候,判断被选定对象可以用if或者switch,如 switch(getQuailiedClassName(currentObj)){ case "shapeClass": case "textClass": currentObj.setFillColor(newColor); break; case "mcClass": //do nothing break; } 但是,文本还可以有动态文本,静态文本,输入文本等子,形状可能有矩形,圆形等子,那么,你目前还是有办法可以处理这个问题: switch(getQuailiedClassName(currentObj)){ case "shapeClass": case "textClass": case "triangleClass": case "rectangleClass": case "dynamicTextClass": case "staticTextClass": case "inputTextClass": currentObj.setFillColor(newColor); break; case "mcClass": //do nothing break; } 多麻烦啊~而且当继承结构复杂的时候,都不知道该写多少句了。因此,getQualifiedSuperclassName就在这里起了点作用。可以检查其超是否为shapeClass或者textClass。 但 是,这个函数只能检查到上一级的名,若继承结构复杂,可能有的继承两至三级甚至更多,在不知道继承级别的情况下,用 getQualifiedSuperclassName想知道对象的继承关系链里是否存在textClass或者shapeClass,就只能通过遍历至 顶级来检验了......不但麻烦,而且效率低。 is运算符诞生啦!这一运算符可以检验某对象是否为指定的实例,只要指定在继承关系链中,都返回true。另外也包括接口。也就是说,假设my_spr是一个Sprite的实例,那么下面的三个表达式都输出true trace(my_spr is Sprite); trace(my_spr is DisplayObjectContainer); trace(my_spr is IEventDispatcher); 回到刚才说的那个选定对象的问题。假设舞台上现在既有MC,又有形状,也有文本。而且形状有圆形,矩形等子的实例,文本有静态文本和动态文本。那么,当选定一个对象时,要确定该对象是否具有颜色填充的功能,就可以将上面的代码简化为: if((currentObj is textClass) or (currentObj is shapeClass)){ currentObj.setFillColor(newColor); }else if(currentObj is mcClass){ //do nothing } 代码得到了简化,可惜的是,其适应性还是相当有限,如果可以进行颜色填充的也有很多,不止textClass和shapeClass的话,此段代码还是要重复写很多很长的“排比句”。 这时,接口起到了作用。因为textClass和shapeClass都是IColorProcessor的接口实现,所以,按照is的运算规则,上面的代码就可以简化成 if((currentObj is IColorProcessor)){ currentObj.setFillColor(newColor); }else if(currentObj is mcClass){ //do nothing } 那么,只要具有填充颜色功能的都实现IColorProcessor接口,就返回true,就可以进行颜色填充,而不需要再检查具体是什么实现该接口了,也不用考虑继承关系,多方便。 既然如此,那么为什么不能用“抽象”代替接口呢?如果textClass和shapeClass都继承colorProcessor,然后检查currentObj is colorProcessor不也一样嘛?接口有何种特性是抽象不具备的呢? 至此,我终于没办法了,要翻Java的技术文章来看,了解下接口和抽象的区别所在。 在我所看到的文章中,貌似都认为抽象的优势比接口还大,不过却推荐使用接口,而不用抽象。看到那些文章后面的地方,终于茅塞顿开啦~~ 在讲接口的优势之前,我先继续刚才的Flash IDE开发问题。 现在,假设你开发到Flash 8,要添加上滤镜功能,但是滤镜只可以加在文本和MC上,那么,你可以先定义一个“抽象”: package{ public class filterProcessor{ public function setFilters(filt_arr:Array):void{ } } } 然后由mcClass来继承: package{ public class mcClass extends filterProcessor{ override public function setFilters(filt_arr:Array):void{ } } } 至于文本,同样地,可以用: package{ public class textClass extends filterProcessor{ override public function setFilters(filt_arr:Array):void{ } } } 文本这里就出问题了,这么写,之前文本继承的colorProcessor就没有了。但是,在AS3里,你不能这么写: package{ public class textClass extends filterProcessor extends colorProcessor{ override public function setFilters(filt_arr:Array):void{ } } } 也不可以写成: package{ public class textClass extends filterProcessor,colorProceessor{ override public function setFilters(filt_arr:Array):void{ } } } 那 么,如果想同时继承这两个,该怎么办呢?你不可以说先让colorProcessor和filterProcessor相互继承,假如颜色处理器继承了 滤镜处理器,那将意味着,形状也可以设置滤镜(这就错掉啦)。如果反过来,就会导致MC可以进行颜色填充(也不行啊)。 在这种情况下,接口的优势就体现出来啦。 原来,接口和抽象相比,多出的一个优势在于(仅限JavaAS3),一个可以实现多个接口,但是不能继承多个。所以,如果在这里改用接口,就一切都好解决了。先定义两个接口: package{ public interface IColorProcessor{ function setFillColor(color:uint):void; } } package{ public interface IFilterProcessor{ function setFilters(filt_arr:Array):void; } } 然后,形状,文本和MC就分别用如下的方式实现接口: package{ public class shapeClass implements IColorProcessor{ public function setFillColor(color:uint):void{ } } } package{ public class textClass implements IColorProcessor,IFilterProcessor{ public function setFillColor(color:uint):void{ } } } package{ public class mcClass implements IFilterProcessor{ public function setFillColor(color:uint):void{ } } } 这样实现了接口以后,在舞台上假如形状,MC,文本都存在的话,你也不需要检查他们是什么了,只要了解他们实现的接口就OK。 if(currentObj is IColorProcessor){ (currentObj as IColorProcessor).setFillColor(newColor); } if(currentObj is IFilterProcessor){ (currentObj as IFilterProcessor).setFilters(filt_arr); } 可 见,定义了接口,在处理多种型的对象过程中会方便很多(可能有人会说,假若方法真的不存在,用try...catch不一样可以处理掉嘛.....,不 过......用这样的处理错误方法,在对象多的时候,运行起来的状况会怎样呢?)。从研究接口用处的过程中,我们发现,接口的产生其实是源于JavaAS3多态(多继承)的限制。为了可以更好地对的特性进行描述,判断处理,接口就显得相当有必要了。 _____________________________________ 讲到现在,我发现自己似乎还没有讲明白问题。但是这个时候我MS已经想到了一个更为实际的例子: 刚 讲了中国人和外国人都继承了人,现在,假设要对中国人和外国人再一次进行分,都按性别再分别对中国人和外国人进行分。假如全部用来做的话,就是先 有一个最顶级的人,接着就是中国人和外国人,男人和女人,接着就是中国男人,中国女人,外国男人,外国女人。 前面说了,AS3Java不能继承多个(前面没看的也没关系,现在你知道就可以了)。所以,你的继承可以有两种策略,不过,顶级的人是无可争议的了。 package{ public class person{ } } 然后,第一种策略,就是先把人分成中国人和外国人: package{ public class Chinese extends person{ } } package{ public class Foreigner extends person{ } } 接着再把他们分别分成男和女的: package{ public class Chinese_man extends Chinese{ } } package{ public class Chinese_woman extends Chinese{ } } package{ public class Foreign_man extends Foreigner{ } } package{ public class Foreign_woman extends Foreigner{ } } 第二种策略,跟第一种策略相反。先按性别分,再按地区分: package{ public class man extends person{ } } package{ public class woman extends person{ } } 接下来的就是 package{ public class Chinese_man extends man{ } } package{ public class Chinese_woman extends woman{ } } package{ public class Foreign_man extends man{ } } package{ public class Foreign_woman extends woman{ } } 现在分好了,开始要让他们做两件事情: 1 让外国人在中国环游一周; 2 组织全体女性到联合国的妇联开会。 按 照第一种策略的话,让外国人在中国环游一周,就只需要让所有外国人的实例都调用一个环游的方法就可以了。但是,若要完成第二个任务,就需要先对中国的女 性调用一个组织开会的方法,再对外国女性调用一个组织开会的方法。相反,第二种策略就让第一个任务完成得比较麻烦,第二个任务就相对方便。鱼和熊掌,两者 不可兼得。 但是,如果使用接口呢?情况就大大不同。 在定义了人的接口以后: package{ public interface IPerson{ } } 再定义四个接口:男人,女人,中国人,外国人: package{ public interface IMan extends IPerson{ } package{ public interface IWoman extends IPerson{ } package{ public interface IForeigner extends IPerson{ } package{ public interface IChinese extends IPerson{ } 接下来就定义中国男人,中国女人,外国男人,外国女人。这时可以用了。 package{ public class Chinese_man implements IMan,IChinese{ } } package{ public class Chinese_woman implements IWoman,IChinese{ } } package{ public class Foreign_man implements IMan,IForeigner{ } } package{ public class Foreign_woman implements IWoan,IForeigner{ } } 同 样完成上面的两个任务,第一个,只需要调用实现接口IForeigner的就OK了,同样地,第二个也只需要调用实现接口IWoman的。当分区分 细,不再按中国人外国人分,而要按照国籍来分成200多个的时候,或者再细分至省和洲的时候,这一做法的优势就更为明显了。 总结起来,可以得知,在的继承结构不能仅用树状去表示,如上面的具有交叉继承结构的时候,就建议用接口了。但是,如果是简单的树状结构,我觉得还是用继承好些,毕竟这样的做法也有维护上的优势。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值