加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ActionScript中包和命名空间详解

发布时间:2020-12-15 07:09:33 所属栏目:百科 来源:网络整理
导读:包和命名空间? 包和命名空间是两个相关的概念。使用包,可以通过有利于共享代码并尽可能减少命名冲突的方式将多个类 定义捆绑在一起。使用命名空间,可以控制标识符(如属性名和方法名)的可见性。无论命名空间位于包的内部 还是外部,都可以应用于代码。包
包和命名空间? 包和命名空间是两个相关的概念。使用包,可以通过有利于共享代码并尽可能减少命名冲突的方式将多个类 定义捆绑在一起。使用命名空间,可以控制标识符(如属性名和方法名)的可见性。无论命名空间位于包的内部 还是外部,都可以应用于代码。包可用于组织类文件,命名空间可用于管理各个属性和方法的可见性。? ? 包? 在 ?ActionScript 3.0 ?中,包是用命名空间实现的,但包和命名空间并不同义。在声明包时,可以隐式创建一 个特殊类型的命名空间并保证它在编译时是已知的。显式创建的命名空间在编译时不必是已知的。? 类位于包中,因此编译器在编译时会自动将其类名称限定为完全限定名称,编译器还限定任何属性或方法的 名称。完全限定的包引用点运算符 ?( .) ?来表示。? 许多开发人员(尤其是那些具有 Java 编程背景的人)可能会选择只将类放在包的顶级。但是,ActionScript? 3.0 不但支持将类放在包的顶级,而且还支持将变量、函数甚至语句放在包的顶级。此功能的一个高级用法是, 在包的顶级定义一个命名空间,以便它对于该包中的所有类均可用。但是,请注意,在包的顶级只允许使用两个 访问说明符:public 和 internal。Java 允许将嵌套类声明为私有,而 ActionScript 3.0 则不同,它既不支 持嵌套类也不支持私有类。? 您还可以在包名称中嵌入点来创建嵌套包,这样就可以创建包的分层结构。? 创建包? ActionScript 3.0 允许在一个源文件中包括多个类,但是,每个文件中只有一个类可供该文件外部的代码 使用。换言之,每个文件中只有一个类可以在包声明中进行声明。您必须在包定义的外部声明其它任何类,以使 这些类对于该源文件外部的代码不可见。在包定义内部声明的类的名称必须与源文件的名称匹配。? 在 ActionScript 3.0 中,尽管包仍表示目录,但是它现在不只包含类。在 ActionScript 3.0 中,使用? package 语句来声明包,这意味着您还可以在包的顶级声明变量、函数和命名空间,甚至还可以在包的顶级包括 可执行语句。如果在包的顶级声明变量、函数或命名空间,则在顶级只能使用 public 和 internal 属性,并且 每个文件中只能有一个包级声明使用 public 属性(无论该声明是类声明、变量声明、函数声明还是命名空间声 明)。 ? 包的作用是组织代码并防止名称冲突。您不应将包的概念与类继承这一不相关的概念混淆。位于同一个包中 的两个类具有共同的命名空间,但是它们在其它任何方面都不必相关。同样,在语义方面,嵌套包可以与其父包 无关。? 导入包? 如果您希望使用位于某个包内部的特定类,则必须导入该包或该类。? 通常,import 语句越具体越好。如果您只打算使用包中的某个类,则应只导入该类,而不应导入该类所属 的整个包。导入整个包可能会导致意外的名称冲突。? 还必须将定义包或类的源代码放在类路径 内部。类路径是用户定义的本地目录路径列表,它决定了编译器 将在何处搜索导入的包和类。类路径有时称为"生成路径"或"源路径"。 ? 在正确地导入类或包之后,可以使用类的完全限定名称,也可以只使用类名称本身。? 当同名的类、方法或属性会导致代码不明确时,完全限定的名称非常有用,但是,如果将它用于所有的标识 符,则会使代码变得难以管理。包的嵌套级别越高,代码的可读性越差。如果您确信不明确的标识符不会导致问 题,就可以通过使用简单的标识符来提高代码的可读性。? 如果您尝试使用标识符名称,而不先导入相应的包或类,编译器将找不到类定义。另一方面,即便您导入了 包或类,只要尝试定义的名称与所导入的名称冲突,也会产生错误。? 创建包时,该包的所有成员的默认访问说明符是 internal,这意味着,默认情况下,包成员仅对其所在包 的其它成员可见。如果您希望某个类对包外部的代码可用,则必须将该类声明为 public。? 不能将 public 属性应用于包声明。 ? 完全限定的名称可用来解决在使用包时可能发生的名称冲突。如果您导入两个包,但它们用同一个标识符来 定义类,就可能会发生名称冲突。要解决此冲突,必须使用每个类的完全限定名称。? ActionScript 3.0有一个include 指令,但是它的作用不是为了导入类和包。要在ActionScript 3.0中导 入类或包,必须使用 import 语句,并将包含该包的源文件放在类路径中。? 命名空间? 通过命名空间可以控制所创建的属性和方法的可见性。请将 public、private、protected 和 internal 访 问控制说明符视为内置的命名空间。如果这些预定义的访问控制说明符无法满足您的要求,您可以创建自己的命 名空间。 ? 要了解命名空间的工作方式,有必要先了解属性或方法的名称总是包含两部分:标识符和命名空间。标识符 通常被视为名称。? 只要定义不以命名空间属性开头,就会用默认 internal 命名空间限定其名称,这意味着,它们仅对同一个 包中的调用方可见。如果编译器设置为严格模式,则编译器会发出一个警告,指明 internal 命名空间将应用于 没有命名空间属性的任何标识符。为了确保标识符可在任何位置使用,您必须在标识符名称的前面明确加上? public 属性。? 使用命名空间时,应遵循以下三个基本步骤。? 第一,必须使用 namespace 关键字来定义命名空间。例如,下面的代码定义 version1 命名空间:? namespace version1;? 第二,在属性或方法声明中,使用命名空间(而非访问控制说明符)来应用命名空间。下面的示例将一个名 为 myFunction() 的函数放在 version1 命名空间中:? version1 function myFunction() {}? 第三,在应用了该命名空间后,可以使用 use 指令引用它,也可以使用该命名空间来限定标识符的名称。 下面的示例通过 use 指令来引用 myFunction() 函数:? use namespace version1;? myFunction();? 您还可以使用限定名称来引用 myFunction() 函数,如下面的示例所示:? version1::myFunction();? 定义命名空间? 命名空间中包含一个名为统一资源标识符 ?(URI) ?的值,该值有时称为命名空间名称。使用 ?URI ?可确保命 名空间定义的唯一性。(统一资源标识符 ?(Uniform Resource Identifier,URI) ?用于唯一地标识元素或属性的数字 或名称。URI ?包括统一资源名称 ?(URN) ?和统一资源定位器 ?(URL)。) ? ?? 可通过使用以下两种方法之一来声明命名空间定义,以创建命名空间:像定义 ?XML ?命名空间那样使用显 式 ?URI ?定义命名空间;省略 ?URI。? 下面的示例说明如何使用 ?URI ?来定义命名空间:? namespace flash_proxy = "http://www.adobe.com/flash/proxy";? URI ?用作该命名空间的唯一标识字符串。如果您省略 ?URI(如下面的示例所示),则编译器将创建一个唯 一的内部标识字符串来代替 ?URI。您对于这个内部标识字符串不具有访问权限。? namespace flash_proxy;? 在定义了命名空间(具有 ?URI ?或没有 ?URI)后,就不能在同一个作用域内重新定义该命名空间。如果尝试 定义的命名空间以前在同一个作用域内定义过,则将生成编译器错误。 ?? 如果在某个包或类中定义了一个命名空间,则该命名空间可能对于此包或类外部的代码不可见,除非使用了 相应的访问控制说明符。例如,下面的代码显示了在 ?flash.utils ?包中定义的 ?flash_proxy ?命名空间。在下面的示 例中,缺乏访问控制说明符意味着 ?flash_proxy ?命名空间将仅对于 ?flash.utils ?包内部的代码可见,而对于该包外 部的任何代码都不可见:? package flash.utils? {? ? ? ? ? namespace flash_proxy;? }? 下面的代码使用 ?public ?属性以使 ?flash_proxy ?命名空间对该包外部的代码可见:? package flash.utils? {? ? ? ? ? public namespace flash_proxy;? }? 应用命名空间? 应用命名空间意味着在命名空间中放置定义。可以放在命名空间中的定义包括函数、变量和常量(不能将类 放在自定义命名空间中)。 ? 例如,请考虑一个使用 public 访问控制命名空间声明的函数。在函数的定义中使用 public 属性会将该函 数放在 public 命名空间中,从而使该函数对于所有的代码都可用。在定义了某个命名空间之后,可以按照与使 用 public 属性相同的方式来使用所定义的命名空间,该定义将对于可以引用您的自定义命名空间的代码可用。 ? 例如,如果您定义一个名为 example1 的命名空间,则可以添加一个名为 myFunction() 的方法并将 example1? 用作属性,如下面的示例所示:? namespace example1;? class someClass? {? ? ? example1 myFunction() {}? }? 如果在声明 myFunction() 方法时将 example1 命名空间用作属性,则意味着该方法属于 example1 命名空 间。? 在应用命名空间时,应切记以下几点:? · ?对于每个声明只能应用一个命名空间。 ? · ?不能一次将同一个命名空间属性应用于多个定义。换言之,如果您希望将自己的命名空间应用于 10 个 不同的函数,则必须将该命名空间作为属性分别添加到这 10 个函数的定义中。 ? · ?如果您应用了命名空间,则不能同时指定访问控制说明符,因为命名空间和访问控制说明符是互斥的。 换言之,如果应用了命名空间,就不能将函数或属性声明为 public、private、protected 或 internal。 ? 引用命名空间? 在使用借助于任何访问控制命名空间(如 public、private、protected 和 internal)声明的方法或属性 时,无需显式引用命名空间。这是因为对于这些特殊命名空间的访问由上下文控制。例如,放在 private 命名 空间中的定义会自动对于同一个类中的代码可用。但是,对于您所定义的命名空间,并不存在这样的上下文相关 性。要使用已经放在某个自定义命名空间中的方法或属性,必须引用该命名空间。? 可以用 use namespace 指令来引用命名空间,也可以使用名称限定符 (::) 来引用命名空间限定名称。用? use namespace 指令引用命名空间会打开该命名空间,这样它便可以应用于任何未限定的标识符。例如,如果您 已经定义了 example1 命名空间,则可以通过使用 use namespace example1 来访问该命名空间中的名称:? use namespace example1;? myFunction();? 一次可以打开多个命名空间。在使用 use namespace 打开了某个命名空间之后,它会在打开它的整个代码 块中保持打开状态。不能显式关闭命名空间。? 但是,如果同时打开多个命名空间则会增加发生名称冲突的可能性。如果您不愿意打开命名空间,则可以用 命名空间和名称限定符来限定方法或属性名,从而避免使用 use namespace 指令。例如,下面的代码说明如何 用 example1 命名空间来限定 myFunction() 名称:? example1::myFunction();? 使用命名空间? 在 ?Flash Player API ?中的 ?flash.utils.Proxy ?类中,可以找到用来防止名称冲突的命名空间的实例。Proxy ?类 取代了 ?ActionScript 2.0 ?中的 ?Object.__resolve ?属性,可用来截获对未定义的属性或方法的引用,以免发生错误。 为了避免名称冲突,将 ?Proxy ?类的所有方法都放在 ?flash_proxy ?命名空间中。? 为了更好地了解 ?flash_proxy ?命名空间的使用方法,您需要了解如何使用 ?Proxy ?类。Proxy ?类的功能仅对于 继承它的类可用。换言之,如果您要对某个对象使用 ?Proxy ?类的方法,则该对象的类定义必须是对 ?Proxy ?类的 扩展。例如,如果您希望截获对未定义的方法的调用,则应扩展 ?Proxy ?类,然后覆盖 ?Proxy ?类的 ?callProperty()? 方法。 ?? 前面已讲到,实现命名空间的过程通常分为三步,即定义、应用然后引用命名空间。但是,由于您从不显式 调用 ?Proxy ?类的任何方法,因此只是定义和应用 ?flash_proxy ?命名空间,而从不引用它。Flash Player API ?定义? flash_proxy ?命名空间并在 ?Proxy ?类中应用它。在您的代码中,只需要将 ?flash_proxy ?命名空间应用于扩展 ?Proxy? 类的类。 ?? flash_proxy ?命名空间按照与下面类似的方法在 ?flash.utils ?包中定义:? package flash.utils? {? ? ? ? ? public namespace flash_proxy;? }? ?? 该命名空间将应用于 ?Proxy ?类的方法,如下面摘自 ?Proxy ?类的代码所示:? public class Proxy? {? ? ? ? ? flash_proxy function callProperty(name:*,... rest):*? ? ? ? ? flash_proxy function deleteProperty(name:*):Boolean? ? ? ? ? ...? }? 如下面的代码所示,您必须先导入 ?Proxy ?类和 ?flash_proxy ?命名空间。随后必须声明自己的类,以便它对? Proxy ?类进行扩展(如果是在严格模式下进行编译,则还必须添加 ?dynamic ?属性)。在覆盖 ?callProperty() ?方法 时,必须使用 ?flash_proxy ?命名空间。? package? {? ? ? ? ? import flash.utils.Proxy;? ? ? ? ? import flash.utils.flash_proxy;? ? ? ? ? ? dynamic class MyProxy extends Proxy? ? ? ? ? {? ? ? ? ? ? ? ? ? flash_proxy override function callProperty(name:*,...rest):*? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? trace("method call intercepted: " + name);? ? ? ? ? ? ? ? ? }? ? ? ? ? }? }? 如果您创建 ?MyProxy ?类的一个实例,并调用一个未定义的方法(如在下面的示例中调用的 ?testing() ?方法), Proxy ?对象将截获对该方法的调用,并执行覆盖后的 ?callProperty() ?方法内部的语句(在本例中为一个简单的? trace() ?语句)。? var mySample:MyProxy = new MyProxy();? mySample.testing(); // 已截获方法调用:测试? 将 ?Proxy ?类的方法放在 ?flash_proxy ?命名空间内部有两个好处。第一个好处是,在扩展 ?Proxy ?类的任何类 的公共接口中,拥有单独的命名空间可提高代码的可读性。(在 ?Proxy ?类中大约有 ?12 ?个可以覆盖的方法,所 有这些方法都不能直接调用。将所有这些方法都放在公共命名空间中可能会引起混淆。)第二个好处是,当 ?Proxy? 子类中包含名称与 ?Proxy ?类方法的名称匹配的实例方法时,使用 ?flash_proxy ?命名空间可避免名称冲突。例如, 您可能希望将自己的某个方法命名为 ?callProperty() 。下面的代码是可接受的,因为您所用的 ?callProperty() ?方法 位于另一个命名空间中:? dynamic class MyProxy extends Proxy? {? ? ? ? ? public function callProperty() {}? ? ? ? ? flash_proxy override function callProperty(name:*,...rest):*? ? ? ? ? {? ? ? ? ? ? ? ? ? trace("method call intercepted: " + name);? ? ? ? ? }? }? 当您希望以一种无法由四个访问控制说明符(public、private 、internal ?和 ?protected)实现的方式提供对方法 或属性的访问时,命名空间也可能会非常有用。例如,您可能有几个分散在多个包中的实用程序方法。您希望这 些方法对于您的所有包均可用,但是您不希望这些方法成为公共方法。为此,您可以创建一个新的命名空间,并 将它用作您自己的特殊访问控制说明符。 ?? 下面的示例使用用户定义的命名空间将两个位于不同包中的函数组合在一起。通过将它们组合到同一个命名 空间中,可以通过一条 ?use namespace ?语句使这两个函数对于某个类或某个包均可见。? ? 本示例使用四个文件来说明此方法。所有的文件都必须位于您的类路径中。第一个文件 ?(myInternal.as) ?用 来定义 ?myInternal ?命名空间。由于该文件位于名为 ?example ?的包中,因此您必须将该文件放在名为 ?example ?的 文件夹中。该命名空间标记为 ?public ,因此可以导入到其它包中。 ?? // example ?文件夹中的 ?myInternal.as? package example? {? ? ? ? ? public namespace myInternal = "http://www.adobe.com/2006/actionscript/examples";? }? 第二个文件 ?(Utility.as) ?和第三个文件 ?(Helper.as) ?定义的类中包含应可供其它包使用的方法。Utility ?类位于? example.alpha ?包中,这意味着该文件应放在 ?example ?文件夹下的 ?alpha ?子文件夹中。Helper ?类位于? example.beta ?包中,这意味着该文件应放在 ?example ?文件夹下的 ?beta ?子文件夹中。这两个包(example.alpha ?和? example.beta)在使用命名空间之前必须先导入它。? // example/alpha ?文件夹中的 ?Utility.as? package example.alpha? {? ? ? ? ? import example.myInternal;? ? ? ? ? ? ? ? ? ? public class Utility? ? ? ? ? {? ? ? ? ? ? ? ? ? private static var _taskCounter:int = 0;? ? ? ? ? ? ? ? ? ? ? ? ? ? public static function someTask()? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? _taskCounter++;? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? myInternal static function get taskCounter():int? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? return _taskCounter;? ? ? ? ? ? ? ? ? }? ? ? ? ? }? }? ? // example/beta ?文件夹中的 ?Helper.as? package example.beta? {? ? ? ? ? import example.myInternal;? ? ? ? ? ? ? ? ? ? public class Helper? ? ? ? ? {? ? ? ? ? ? ? ? ? private static var _timeStamp:Date;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? public static function someTask()? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? _timeStamp = new Date();? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? myInternal static function get lastCalled():Date? ? ? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? return _timeStamp;? ? ? ? ? ? ? ? ? }? ? ? ? ? }? }? 第四个文件 ?(NamespaceUseCase.as) ?是主应用程序类,应是 ?example ?文件夹的同级。在 ?Adobe Flash CS3? Professional 中,将此类用作 ?FLA ?的文档类。NamespaceUseCase 类还导入 ?myInternal ?命名空间,并使用它来 调用位于其它包中的两个静态方法。在本示例中,使用静态方法的目的仅在于简化代码。在 ?myInternal ?命名空 间中既可以放置静态方法也可以放置实例方法。? // NamespaceUseCase.as? package? {? ? ? ? ? import flash.display.MovieClip;? ? ? ? ? import example.myInternal; ? ? ? ? ? ? ?// ?导入命名空间? ? ? ? ? import example.alpha.Utility; ? ? ? ?// ?导入 ?Utility ?类? ? ? ? ? import example.beta.Helper; ? ? ? ? ? ?// ?导入 ?Helper ?类? ? ? ? ? ? ? ? ? ? public class NamespaceUseCase extends MovieClip? ? ? ? ? {? ? ? ? ? ? ? ? ? public function NamespaceUseCase()? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? use namespace myInternal;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Utility.someTask();? ? ? ? ? ? ? ? ? ? ? ? ? Utility.someTask();? ? ? ? ? ? ? ? ? ? ? ? ? trace(Utility.taskCounter); // 2? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Helper.someTask();? ? ? ? ? ? ? ? ? ? ? ? ? trace(Helper.lastCalled); ? ? ?// [ 上次调用 ?someTask() ?的时间]? ? ? ? ? ? ? ? ? }? ? ? ? ? }? }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读