经典写法4:
http://hi.baidu.com/flgdzkthmdbqtxr/item/6195ad8dd2e9c21fc2162706
问题描述:在ActionScript3.0的API中,DisplayObjectContainer作为抽象基类不能被实例化,而他的子类却可以实例化。在程序设计中,可能我们也会需要写一个基类,这个基类从DisplayObjectContainer继承而来,我也希望这个基类不能被实例化,而他的子类可以实例化。如何才能实现?
问题分析:首先,我们自己定义一个抽象基类,然后写一个子类继承他,并且要求实现这个抽象基类不能被实例化,而子类可以实例化。这样的情况是肯定可行的(ActionScript3.0的API中的类结构已经充分说明了这一点)。在我们确定了这样一种方式可行之后,接下来我们需要整合手头上所拥有的一些资源,然后实现这个想法。
面向对象回顾(在这里主要在语言层面上讨论面向对象的实现方式): 在ActionScript3.0中,面向对象基本和java类似,定义类使用关键字class,类语法如下: - 访问修饰符(公有、保护、默认) 类修饰符(final) class 类名
- {
- 类属性
- 类的构造方法
- 类的方法
- }
复制代码感叹一下,如果ActionScript3.0和java一样存在抽象类就好了,这样的话,我们只需要将这个类设置为抽象的,就能够达到我们的目的。但是很遗憾,ActionScript3.0中并不支持抽象类。也就是说,我们无法找到一个能够直接实现我们想法的关键字。既然无法在类定义上做文章,那么我们也就只能把目光放到类的主体之上了。
解决思路和解决方案以及结果: 首先,我面临的是ActionScript3.0类结构设计相关的一些知识,我手头上最全的资料就是ActionScript3.0的API(实际上我对AS3的学习基本上都是通过API完成的)。而且,我所要做的类结构在API里面应该也会有体现。这样想着,我打开了API,看到了如下信息: DisplayObjectContainer 类是可以包含子对象的所有对象的抽象基类。无法直接对其进行实例化;调用 new DisplayObjectContainer() 构造函数会引发 ArgumentError 异常。 这个是显示对象容器的基类,他本身不能被实例化,但是他的子类Sprite是我们用来做页面显示时使用的最多的一个类。稍微留心一个我们就能发现,这个DisplayObjectContainer类没有构造方法,难道这个就是他不能被实例化的原因?难道只要不写构造函数就算是抽象类?好,终于有点眉目了,既然想到了,就做一下。我写了下面这个示例: - package
- {
- public final class Two{}
- }
复制代码这个类没有构造方法,然后我在主类中去实例化这个类,难道这样就OK了?呼呼,实际上,我得到了正确结果,程序没有报错, AVM2告诉我,这样是可以的。原来AS3中的类和Java中的一样,如果你没有写构造方法,那么它在执行的时候,主动给你创建一个空的构造方法。为了验证这个想法,我可以在上面的代码中加入了一个简单的方法,然后在外部实例化这个类得到一个对象,然后再使用这个对象去调用方法,结果方法被正确调用。了解到一个小知识,但是这个并不是我想要的结果,我们还得继续往下想。
在java中,构造方法可以被定义为私有的或者是公共的,这样的话,我们就能够通过访问修饰符控制构造方法的调用,那么在AS3中是不是也能够这样呢?这样想着,我写了下面这个示例: - package {
- import flash.display.Sprite;
- public class Show extends Sprite
- {
- private function Show(){}
- }
- }
复制代码在java中,这么写是没有问题的,但是遗憾的是,在AS3中这么写了之后,FB3告诉我:构造函数只能够被声明为public的。AS3中的类不能被定义为抽象的,AS3中的构造方法也不能够修饰为私有的,那么我们想定义一个自身不能实例化而子类能够实例化的类难道是不能够实现的吗?但问题是,AS3的API中也有类似的结构,而且已经被实现了啊?或者说,AS3只是在内部实现了这种抽象类机制,他并没有把这种定义方法对外公布? 于是我去找到了系统中已经存在的写法来了一次测试,代码如下: - package {
- import flash.display.DisplayObject;
- import flash.display.Sprite;
- public class Show extends Sprite
- {
- public function Show()
- {
- new DisplayObject();
- }
- }
- }
复制代码让我惊喜的是,编译没有出错,只是执行的时候出错了,错误提示如下: - ArgumentError: Error #2012: 无法实例化 DisplayObject$ 类。
- at Show()[E:\MyAsGame\Show\src\Show.as:9]
复制代码编译没有出错,意味着这样的写法在语法上是没有问题的,也就是说,DisplayObject类确实存在构造方法。那么执行的时候报错,是不是意味着构造里面存在逻辑来判断当前是否可以正常调用构造方法?如果我的猜想是对的,那么也就意味着我能够找到一个方法来判断调用构造函数的是他自身还是他的子类,也就是说,我需要找到一个办法获得调用方法的对象(也就是方法的调用者)。
值得庆幸的是,我在之前的一个项目中曾经去思考过类似的问题,并且找到了一个好的方法:[url=]getQualifiedClassName[/url]()。注:如果你没有过和我类似的经历的话,找这个方法可能需要一些时间。
好的,终于万事具备了,根据之前的逻辑,于是我写下了如下测试代码:
这个是我自定义的抽象类,它继承自Sprite。 - package
- {
- import flash.display.Sprite;
- import flash.utils.getQualifiedClassName;
- public class MyAbstartClass extends Sprite
- {
- public function MyAbstartClass()
- {
- trace(getQualifiedClassName(this));
- if(getQualifiedClassName(this)=="MyAbstartClass")
- {
- throw new ArgumentError("无法实例化类"+getQualifiedClassName(this));
- }
- }
- }
- }
复制代码这个是我所写的抽象类的子类: - package
- {
- public class SonClass extends MyAbstartClass
- {
- public function SonClass()
- {
- super();
- }
- }
- }
复制代码最后是我的测试类: - package {
- import flash.display.DisplayObject;
- import flash.display.Sprite;
- public class Show extends Sprite
- {
- public function Show()
- {
- //new SonClass();
- new MyAbstartClass();
- }
- }
- }
复制代码在测试类中,分别放开两句实例化的代码,我们就能够得到想要的结果:我定义了一个类,但是这个类不能被直接实例化,而他的子类可以被正常实例化。
最后,可能大家还会有一点疑问,我在刚开始思考这个问题的时候,是说我自己所定义的这个基类需要从DisplayObjectContainer继承而来,其实意思应该很明白,我就是想要这个自定义的基类为一个显示对象容器。但是为什么我最后写出来的东西和最初的不一样呢?如果能想到这个,就证明你是真的很用心的去看了上面的文字。其实并不是我不想依照刚开始的问题去找到针对性的方法,而是不得已而为之!至于为什么,这得从我们使用的一个关键函数说起!
函数:[url=]getQualifiedClassName[/url](value:*):String
返回对象的完全限定类名。
参数
value: — 需要完全限定类名称的对象。可以将任何 ActionScript 值传递给此方法,包括所有可用的 ActionScript 类型、对象实例、原始类型(如 uint)和类对象。
返回
— 包含完全限定类名称的字符串。
这个函数的意思是,获得你所传入的数据的类的全名。什么是类的全名?其实就是指你当前这个类的完整类名(即包含所在包的类名,如:flash.display::Sprite)。也就是说,通过这样的方式获得的类名是包含包名的。这对于我们这个程序有意义吗?其实意义是很明显的!在AS3的API中,我们是无法去直接实例化我们所自定义的DisplayObjectContainer类的子类的。这一点在这里就不直接给大家测试用例了,大家可以自己尝试着测试一下。而我们在上面所研究出来的抽象类写法是可以通过他任意的一个子类去实例化的。难道API中还有其他用法?好,有这个疑问就是好的。具体要解答这个疑问,我想是需要去看看AS3的源代码才行的了。因为源代码我暂时没有弄到,所以在这就不解答大家这个疑问了,有源代码的,可以给我发一份,大家一起讨论下,感激不尽!最后一个问题,那么我们写的这个抽象类,能实现的和DisplayObjectContainer类一样吗?就是说,自身不能直接被实例化,而且不同包中的子类也不能直接实例化?大家还记得吗?AS3中有这样一个概念:命名空间!能不能给大家一些提示呢?
好吧,就到这,已经废话的够多了。如果有时间的话,我会整理一下把一个完整再现了AS3 API中抽象类机制的类结构展示给大家。
|