| ActionScript 3.0 のプログラミング > ActionScript プログラミングの概要 > ActionScript 言語とシンタックス > パッケージと名前空間 > 名前空間 | |||
名前空間では、作成したプロパティおよびメソッドの可視性を制御することができます。public、private、protected、および internal アクセス制御指定子は、ビルトイン名前空間のようなものです。これらのあらかじめ定義されているアクセス制御指定子が要件を満たさない場合は、独自の名前空間を作成することができます。
ActionScript 実装のシンタックスおよび詳細は XML とは少し異なりますが、XML 名前空間を使い慣れていれば、ここでの説明は新しいものではないかもしれません。これまで名前空間を操作したことがない場合は、概念自体は単純ですが、その実装には特定の用語を習得する必要があります。
名前空間の動作を理解するために、プロパティまたはメソッドの名前には常に識別子と名前空間の 2 つの部分が含まれることを知っておくと役立ちます。識別子は名前のようなものと考えることができます。たとえば、次のクラス定義の識別子は、sampleGreeting と sampleFunction() です。
class SampleCode
{
var sampleGreeting:String;
function sampleFunction () {
trace(sampleGreeting + " from sampleFunction()");
}
}
定義の前に名前空間属性が付けられていない場合、その名前はデフォルトの internal 名前空間によって修飾されます。この場合、定義は同じパッケージ内の呼び出し元に対してのみ表示されます。コンパイラが strict モードに設定されている場合は、名前空間属性を変更せずに internal 名前空間がすべての識別子に適用されることを示す警告がコンパイラから出されます。識別子をどこでも使用できるようにするためには、識別子名の前に public 属性を付ける必要があります。前のコード例では、sampleGreeting および sampleFunction() の両方が名前空間値 internal を持ちます。
名前空間を使用するときは、次の 3 つの手順に従います。最初に、namespace キーワードを使用して名前空間を定義する必要があります。たとえば、次のコードは、version1 名前空間を定義します。
namespace version1;
次に、プロパティまたはメソッドの宣言にアクセス制御指定子ではなく、定義した名前空間を使用して、その名前空間を適用します。次の例では、myFunction() という関数を version1 名前空間に配置します。
version1 function myFunction() {}
3 番目に、名前空間を適用したら、use ディレクティブを使用するか、名前空間で識別子の名前を修飾して、名前空間を参照できます。次の例では、use ディレクティブから myFunction() 関数を参照します。
use namespace version1; myFunction();
次の例に示すように、修飾名を使用して myFunction() 関数を参照することもできます。
version1::myFunction();
名前空間には、名前空間名とも呼ばれる URI (Uniform Resource Identifier) という値が含まれます。URI によって、名前空間定義を一意にすることができます。
次のいずれかの方法で名前空間定義を宣言して、名前空間を作成します。XML 名前空間を定義するように、明示的な URI で名前空間を定義することも、URI を省略することもできます。次の例では、URI を使用して名前空間を定義する方法を示します。
namespace flash_proxy = "http://www.adobe.com/flash/proxy";
URI は、名前空間の一意な ID ストリングになります。次の例のように URI を省略した場合、コンパイラは URI の代わりに一意の内部 ID ストリングを作成します。この内部 ID ストリングにはアクセスできません。
namespace flash_proxy;
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 属性を使用する場合と同様に定義した名前空間を使用でき、カスタム名前空間を参照できるコードでその定義を使用できるようになります。たとえば、次の例に示すように、名前空間 example1 を定義すると、example1 を属性として使用して myFunction() というメソッドを追加できます。
namespace example1;
class someClass
{
example1 myFunction() {}
}
名前空間 example1 を属性として使用して myFunction() メソッドを宣言すると、このメソッドは example1 名前空間に属すことになります。
名前空間を適用する際には、次の点に注意してください。
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 クラスで名前のコンフリクトを防ぐために使用する名前空間の実際例を参照できます。ActionScript 2.0 の Object.__resolve プロパティに代わる Proxy クラスを使用すると、エラーが発生する前に、未定義のプロパティまたはメソッドへの参照を取得できます。名前の競合を防ぐために、Proxy クラスのすべてのメソッドは flash_proxy 名前空間内にあります。
flash_proxy 名前空間の使用方法についての理解を深めるために、Proxy クラスの使用方法を理解する必要があります。Proxy クラスの機能は、Proxy クラスを継承するクラスでのみ使用できます。つまり、オブジェクト上で Proxy クラスのメソッドを使用する場合、そのオブジェクトのクラス定義は Proxy クラスを拡張する必要があります。たとえば、未定義のメソッドへの呼び出しの試みを取得する場合、Proxy クラスを拡張し、Proxy クラスの callProperty() メソッドをオーバーライドします。
名前空間の実装には通常、名前空間の定義、適用、および参照の 3 つの手順を実行します。しかし、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 クラスを拡張するようにクラスを宣言する必要があります。strict モードでコンパイルしている場合は、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(); // method call intercepted: testing
flash_proxy 名前空間内に Proxy クラスのメソッドを配置すると、2 つの利点があります。1 つ目は、別の名前空間があると、Proxy クラスを拡張するクラスのパブリックインターフェイスを整理できます。Proxy クラスには、オーバーライドできるメソッドが 10 個以上ありますが、これらのメソッドは直接呼び出せるように設計されていません。これらすべてをパブリック名前空間に配置すると、混乱の元になります。2 つ目は、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);
}
}
名前空間は、4 つのアクセス制御指定子 (public、private、internal、および protected) ではできない方法でメソッドまたはプロパティにアクセスする場合にも便利です。たとえば、複数のパッケージに分散するいくつかのユーティリティメソッドがあるとします。これらのメソッドをパブリックにしないで、すべてのパッケージで利用できるようにするには、新しい名前空間を作成して、独自のアクセス制御指定子として使用します。
次の例では、ユーザー定義の名前空間を使用して、異なるパッケージにある 2 つの関数をグループ化します。同じ名前空間でグループ化することで、use namespace ステートメントを 1 つ使用して、クラスまたはパッケージに対してこの 2 つの関数を表示できます。
この例では、4 つのファイルを使用してその手法を示します。ファイルはすべてクラスパス内にある必要があります。1 つ目のファイル myInternal.as を使用して myInternal 名前空間を定義します。このファイルは example パッケージにあるため、example という名前のフォルダに配置する必要があります。名前空間は public とマークされているので、他のパッケージに読み込むことができます。
// example フォルダ内の myInternal.as
package example
{
public namespace myInternal = "http://www.adobe.com/2006/actionscript/examples";
}
2 つ目および 3 つ目のファイル "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;
use namespace 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;
use namespace myInternal;
public class Helper
{
private static var _timeStamp:Date;
public static function someTask()
{
_timeStamp = new Date();
}
myInternal static function get lastCalled():Date
{
return _timeStamp;
}
}
}
4 つ目のファイル "NamespaceUseCase.as" はメインアプリケーションクラスです。このファイルは "example" フォルダの兄弟である必要があります。NamespaceUseCase クラスも myInternal 名前空間を読み込み、この名前空間を使用して他のパッケージにある 2 つの静的メソッドを呼び出します。この例では、コードを簡略化するためにのみ静的メソッドを使用します。静的メソッドおよびインスタンスメソッドは両方とも myInternal 名前空間に配置することができます。
// NamespaceUseCase.as
package
{
import flash.display.MovieClip;
import example.myInternal; // 名前空間の読み込み
import example.alpha.Utility; // Utility クラスの読み込み
import example.beta.Helper; // Helper クラスの読み込み
use namespace myInternal;
public class NamespaceUseCase extends MovieClip
{
public function NamespaceUseCase()
{
Utility.someTask();
Utility.someTask();
trace(Utility.taskCounter); // 2
Helper.someTask();
trace(Helper.lastCalled); // [someTask() が最後に呼び出された時刻]
}
}
}
Flex 2.01