home > 過去ログ(2004年以前) > ActionScript 1.0使いのためのActionScript 2.0入門: Part 2
2004/02/27

ActionScript 1.0使いのためのActionScript 2.0入門: Part 2


Joey Lott (www.person13.com)著
北沢 純 (FACEs Project)訳

この記事のパート1で約束したとおり、パート2ではActionScript 2.0の新しいclassシンタックスを検証しよう。始める前に、もしクラスのような一般的なオブジェクト指向概念に関する自分の知識に不安があるなら、まず下の二つの記事をチェックしたほうがいいだろう: http://www.oreillynet.com/pub/a/javascript/2003/08/12/actionscriptckbk.html
http://www.oreillynet.com/pub/a/javascript/2003/08/19/actionscriptckbk.html

この二つの記事では、オブジェクト指向の概念と、ActionScript 1.0におけるクラスの作成について論じているが、必ずしもActionScript 1.0のテクニックの詳細を全て暗記する必要はない。ただ、この記事は、一般的な意味においてクラスやオブジェクトとはどういうものであるかということについて、非常に優れた導入になってくれるはずだ。一度こういうバックグラウンドを身に付けてしまえばこの記事はもっと理解しやすくなるだろう。

ActionScript 2.0におけるクラスの構造

ActionScript 1.0における「クラス」の構造とActionScript 2.0におけるクラスの構造を大雑把にでも比較しようとすると、違いがはっきりするどころかもっと混乱してしまうことだろう。実際のところ、ActionScript 2.0におけるクラスの構造はActionScript 1.0のそれと根本的に異なる。もしあなたがJavaやC#、あるいはVB、PHPといった他の言語におけるクラスの作成についてのバックグラウンドがあるなら、ActionScriptの新しい本格的なクラス構造に万歳を叫びたくなることだろう。これまでActionScript 1.0でしかクラスを作成した経験が無いとしても、たいして心配する必要はない。ActionScript 2.0のシンタックスは前とは違うが、かなり直感的になったと感じるに違いない。ActionScript 2.0でクラスを一週間も書いていれば、どうやってこれまでActionScript 1.0でやってこれたのか不思議に思うはずだ。

まずはじめに、今度新しくできたクラスの構造とシンタックスについて、キーになる点をいくつか挙げてから、それらについてもっと詳しくみていこう。


* ActionScript 2.0のクラスは.asファイルに定義する必要があり、一ファイルあたり一つのクラスでなければならない。
* ActionScript 2.0のクラスの定義は、新しくできたclassキーワードの後にクラス名をつけて、クラスの内容を中括弧で囲んだ形で宣言される:


class Car { // Class definition }


* ActionScript 2.0のクラスはパッケージの中におくことができる。ActionScript 2.0はimportキーワードをサポートしており、これによりパッケージの全体をインポートしたりパッケージ内のクラスを選び出したりすることができる。
* ActionScript 2.0クラスのメンバーはpublic、private、staticを使って宣言することができる。
* ActionScript 2.0クラスは、クラス宣言の中でextendsキーワードを使うことで、他のクラスを継承することができる。
* ActionScript 2.0のクラスはインタフェースを実装(implement)することができる。

うわ! どれも見たことが無く、とっつきにくいと感じるかも知れないが、読み進んでほしい。これら一つ一つをより詳しく説明していくので、実例を使って自分自身で試してみることもできる(あなたがFlash MX 2004もしくはFlash MX Professional 2004を持っていると仮定する)。

ActionScriptクラスファイルを定義する

JavaやC#といった他の言語に馴染みが無い人とっては、クラス単位でファイルに保存するというのは見覚えのない考え方かもしれない。これまでActionScript 1.0を使ってきたのなら、一つの.asファイルどころか.flaファイルの中にさえ複数のクラスを定義できたのだから、なおさらだ。
全てのクラスをファイル毎に、外部.asファイルとして保存するのが好都合である理由は沢山ある。もっとも重要な利点は、もちろん、より組織化(organaized)されるということだ。クラスがちゃんと組織だっているとクラスを保存、配置、管理、配布するのがより簡単になる。あらゆる場所にクラスを定義していると、簡潔さが失われ雑然としてくる。もちろん、二つや三つのクラスで作業しているなら、それが必ずしも大きな問題になるわけではない。しかしActionScript 2.0は我々をActionScriptの新しいパラダイムに導いてくれる。開発者は、あらかじめ組み込まれる機能を提供するためのクラスライブラリを作成、共有することができる。車輪を再発明することなく、自分が以前に作成したものや他の人が作ってくれたものを元にして構築していくことができる。Flash MX 2004をインストールしたときにFirst Run/Classesディレクトリ(とそのサブディレクトリ)に現われる標準のクラス群をみると、Macromediaは既にそのような形に一足跳びに移行してしまっていることがわかる。
ActionScript 1.0のクラスとは違って、ActionScript 2.0のクラスは全て、必ず外部の.asファイルに保存しなければならない。加えて、これらのファイルはクラス名とファイル名が一致していなければならない。例えば、Carという名前のクラスならばCar.asというファイル名にする必要がある。

パッケージを使って作業する

クラスファイルはパッケージに格納することができる。パッケージ(.NETの世界では名前空間と呼ばれる)に馴染みがないなら、クラスを組織化する方法と言っておこう。パッケージには二つの側面がある。第一に、クラス定義ではその宣言の中で自分の属するパッケージを指定する必要がある。次のセクションの該当部分でより詳しく見ていく。第二に、.asファイルはそれに対応したディレクトリもしくはディレクトリ群に保存されなければならない。例えば、あるクラスを持つパッケージがcom.person13なら、そのクラスの.asファイルはcom/person13というディレクトリ構造で保存されなければならない。

パッケージで作業することには、二つの大事な利点がある。一番はっきりしているのは、クラスファイルを組織化する方法が与えられたことにより素早くクラスの配置が行えるようになったということだ。例えば、Flash MX 2004に同梱された(First Run/Classesディレクトリの中にある)クラスセットをみると、UIコンポーネント用のクラスの多くがmx.controlsパッケージの中に統合され、そのためにmx/controlsディレクトリに保存されていることがわかるだろう。パッケージの二番目の利点は、名前の衝突がおこる可能性を回避するのに役立つということだ。同一のパッケージ内では、同じ名前をもった二つのクラスは、存在することができない。これが、どちらが使用したいクラスかをFlashが判断する手段が存在しないからであることは明らかだ。よって、パッケージを全く使用せず全てのクラスを同じディレクトリに保存すると、この問題に行きあたる潜在的可能性がある。もちろん、全てのクラスを自分で書いているなら、それぞれのクラスに確実に一意の名前を与えるようにするのは簡単だ。しかし他人のクラスをダウンロードしてインストールする場合は、同じように管理することができない。クラスがパッケージに格納されていれば、確実にこのようなタイプの名前付け問題が起こらないようにする助けになる。 例えばFlashでは、com.person13パッケージ内のCarクラスとcom.ejepoパッケージ内のCarクラスは名前の衝突を起こさない。

クラスパスを定義する

デフォルトでは、Flashがクラスファイルを探すときはFirst Run/Classesディレクトリをまず最初に見にいく。指定されたクラスをこのディレクトリの中で見つけられなかった場合、Flashは次に、FlashもしくはActionScriptのドキュメントが保存されているディレクトリを見にいく。
クラスパスはFlashがクラスファイルを探すディレクトリのリストである。クラスパスとして追加のディレクトリを指定することもできる。クラスパスを編集するには、編集 > 環境設定からActionScriptタブを選択する。ActionScript 2.0 設定をクリックしてActionScript 設定のダイアログボックスを出す。+ボタンで新しいディレクトリを追加、-ボタンでディレクトリを削除、矢印ボタンで順番を変えられる。


図1: クラスパスを定義する

図1でわかるように、自分のクラスパスにD:\ActionScriptClassesというディレクトリを追加した。これは、Flashが三番目にクラスファイルを探す先が、D:\ActionScriptClassesというディレクトリになったということだ(ちなみに、$(LocalData)は、自分のFlashがインストールされたところのFirst Runディレクトリに設定される)。クラスパスにカスタムディレクトリを追加することは、以下のような理由から推奨される:
* Flashが同梱している全てのクラスが格納されたディレクトリをブラウズするよりも、D:\ActionScriptClassesといったディレクトリをブラウズするほうが簡単だから
* Flashが同梱している全てのクラスが格納されたディレクトリと別のディレクトリに自分のカスタムクラスを全て保存しておけば、自分のファイルを管理するのが簡単になるから。

PrivateメンバーとPublicメンバーを理解する

クラスは、プロパティとメソッドというメンバーから構成されている。もしActionScript 1.0の複雑な機能なもしくはドキュメント化されていない機能を使っているのでない限り、ActionScript 1.0のメンバーは全てpublicである。メンバーがpublicであると言う場合、それはクラス定義の外側からそこにアクセスできるという意味である。例えば、makeという名前のプロパティをもつ Carクラスを作成し、そのプロパティがCarクラスのインスタンスを通じてアクセスできるなら、そのプロパティはpublicである。しかしクラスのプロパティとメソッドをpublicにアクセスできないようにしたいことはよくある。クラスは、内部でしか使われずかつpublicとして公開されることのないプロパティと変数を持つことができる。このようにしたい場合、メンバーをprivateとして宣言すればよい。

注意: これまでJavaやC#など他の言語を使ってきた場合は、ActionScript 2.0のprivateメンバーがJavaやC#におけるprotectedメンバーのような振舞いをすることに注意しなければならない。

あるメンバーをpublicもしくはprivateで宣言するためには、それぞれpublicprivateキーワードを使う。例えば、以下のコードはprivateプロパティを宣言している:


private var _nInterval:Number;


慣習として、クラス内では、ローカルの変数とパラメータとprivateプロパティを区別するために、privateプロパティの名前の最初の文字をアンダースコア(下線)にする。

次のセクションの中では、publicメンバーとprivateメンバーの宣言について見ていこう。privateメンバーとpublicメンバーの実例はこのトピックを正しく理解する助けになるはずだ。次のセクションではpublicメンバーとprivateメンバーの両方を使ったカスタムクラスを作成する。

注意: publicかprivateかを指定しない場合、デフォルトはpublicである。

Staticメンバーを理解する

staticメンバーは、インスタンスからでなくクラスから直接アクセスされるメンバーである。これはActionScript 2.0からの新しい概念ではない。実はFlash 5から、組み込みのクラスにはstaticメンバーがあった。例えば、 Mathクラスは完全にstaticメンバから構成されている。 Mathクラスのインスタンスを作ってそのインスタンス経由でプロパティとメソッドにアクセスするのではなく、常にそのクラス自体をから直接プロパティとメソッドにアクセスする。例を挙げると:


trace(Math.cos(3.14));


cos()メソッドがMathクラスから直接アクセスされていることに注意しよう。 つまりこれがstaticメソッドだ。
ActionScript 2.0のクラスでstaticメンバーを作るには、 宣言時にstaticそしてstaticメンバは、他のstaticでない メンバーと同じく、publicもしくはprivateで修飾可能である。以下にpublic staticメンバの宣言の例を示す。


public static var classname = "Car";


クラスを宣言する

クラス構造を、非常に単純化して言葉で表すと、以下の4つの基本部分にわけられる:
* classキーワードとクラスの名前から成るクラス宣言
* プロパティの宣言
* コンストラクタの宣言
* メソッドの宣言

これらの基本部分をそれぞれより詳細に検証していこう:

クラス宣言

クラスを宣言するには、classキーワードの後にクラスの名前をつける。それからクラス定義を中括弧で囲む。例えば:


class Car { // クラス定義 }


classをパッケージの中に置きたい場合は、クラス宣言の中でクラス名の一部としてパッケージを指定する必要がある。パッケージ名を含むクラス名は、完全修飾クラス名と呼ばれる。例えば、com.person13というパッケージの中にCarクラスを置きたい場合、そのクラス宣言は以下のようになる:


class com.person13.Car { // Class 定義 }


そしてもちろん、クラスをパッケージ内に置くときは、対応するディレクトリにそのクラスファイルを保存しなければならない。com.person13.Carクラスの場合は、Car.asファイルはFlashのクラスパス内でcom/person13というディレクトリ構造の中に保存されなければならない(例えば、クラスパスにD:\ActionScriptClassesが含まれていたら、ファイルはD:\ActionScriptClasses\com\person13\Car.as として保存する)。


プロパティの宣言

プロパティは全てクラス定義の中括弧の内部で宣言する必要がある。また、全てのプロパティはメソッドの外部で宣言しなければならない。慣習として、全てのプロパティはクラス宣言の冒頭部で宣言される。例えば:


class com.person13.Car { private var _sMake:String; private var _sModel:String; private var _nYear:Number; private var _nMiles:Number; private var _nInterval:Number; // 残りのクラス定義 }



コンストラクタの宣言

クラス内にプロパティを宣言したら、次はコンストラクタを宣言する。技術的には、コンストラクタを明示的に宣言しなければ、Flashは空のコンストラクタを暗黙に作成する。しかし、コンストラクタが何もしない場合でも、コンストラクタは明示的に宣言するのが良いやり方だ。
コンストラクタとは、クラスと同じ名前をもつ特別なメソッドであることを覚えておこう。コンストラクタは、クラスの新規インスタンスを生成するnewの実行時に使用される。コンストラクタは通常の関数と同じように宣言され、パラメータを受け取ることができるが、値を返さない。以下はコンストラクタをもったCarクラスの例である:


class com.person13.Car { private var _sMake:String; private var _sModel:String; private var _nYear:Number; private var _nMiles:Number; private var _nInterval:Number; function Car(sMake:String, sModel:String, nYear:Number, nMiles:Number) { _sMake = sMake; _sModel = sModel; _nYear = nYear; _nMiles = nMiles; } // 残りのクラス定義 }


他の一部の言語と違って、ActionScript 2.0ではコンストラクタを オーバーロードできない。

メソッドを宣言する

次にクラスのメソッドを宣言する。functionキーワードと、functionと全く同じ シンタックスとを使って標準の関数と同じようにメソッドを宣言する。 メソッドは関数だが、クラスに関連付けられているということを覚えておこう。 クラス内で関数を宣言するので、Flashはその関数がそのクラス と関連があることを自動的に検知する。標準の関数とメソッドが違うところは、 メソッドは、必要に応じてpublic、private、そしてstaticとして宣言できるということだ。 以下は二つのメソッド--一つはpublicでもう一つはprivate--を持つCarクラスを 定義した例である


class com.person13.Car { private var _sMake:String; private var _sModel:String; private var _nYear:Number; private var _nMiles:Number; private var _nInterval:Number; function Car(sMake:String, sModel:String, nYear:Number, nMiles:Number) { _sMake = sMake; _sModel = sModel; _nYear = nYear; _nMiles = nMiles; } public function drive(nMPH:Number):Void { if(nMPH == null || nMPH == 0) { clearInterval(_nInterval); } else { _nInterval = setInterval(this, "increment", 1000, nMPH); } } private function increment(nMPH:Number):Void { _nMiles += nMPH; } }


Getter/Setterメソッドを使う

getterメソッドとsetterメソッドは特別なメソッドであり、プロパティとしてクラス外部からアクセスできる がクラス内ではメソッドとして定義されている。getterメソッドとsetterメソッドに見込まれている 利点は、このようなメソッドにより、クラス外部のプロパティのような働きをしつつ 内部に洗練されたロジックを持つメンバーが作成可能になるということだ。Carクラスの例では、 車の製造年の値が1866年(自動車が最初に発明された年)より前にならず、走行マイル数が 0以下に設定されることがないようにしたい。加えて、getterメソッドとsetterメソッドには 以下の利点がある:
* クラス内部では例えば_nMilesといったプロパティ名で作業し、milesのようなよりユーザフレンドリーなプロパティ名で値をpublicに公開できるようになる。
* 読み取り専用のプロパティと書き込み専用のプロパティを作成することができる。
* 仮想のプロパティを作成できる---仮想のプロパティとは、クラス内のどの特定のプロパティとも対応せず、内部の値の混合体を元に生成されるプロパティである。

getterメソッドはパラメータを決して受け付けることはなく、常に一つの値を返す。getterメソッドのシンタックスは以下のようになる:


function get externalPropertyName():ReturnType { // return文を含むメソッド定義 }


このメソッドは、他のメソッドと同じく、publicキーワードとstaticキーワード で修飾できるが、getterメソッドをprivateとして宣言することはできない。

以下は、milesプロパティとして_nMilesの値を返す単純なgetterメソッドの例である。


public function get miles():Number { return _nMiles; }


setterメソッドのシンタックスはgetterメソッドのシンタックスとよく似ているが、setterメソッドは必ずパラメータを引数に取り、値を返さず、getキーワードの代わりにsetキーワードを使う。以下が基本シンタックスである:


function set externalPropertyName(parameterName:DataType):Void { // メソッド定義 }


getterメソッドと同じく、setterメソッドもpublicキーワードとstaticキーワード で修飾できるがprivateは使えない。以下に_nMilesというプライベートプロパティに新しい値を代入するsetterメソッドの例を示す。この例では、setterメソッドが、値が必ず0以上になるようにチェックしていることに注意。0以上でなければ、デフォルトの値として0を使う。


public function set miles(nMiles:Number):Void { if(nMiles >= 0) { _nMiles = nMiles; } else { _nMiles = 0; } }


クラスをインポートする

パッケージ内にクラス群を配置する場合、クラスを参照するためには常に完全修飾のクラス名を使う必要がある。これは、もしcom.person13.Carというクラスを作ったとしたらこのクラスのインスタンスを作成するためにはコンストラクタ文がこのようになってしまうことを意味する:


var car:com.person13.Car = new com.person13.Car("Oldsmobile", "Alero", 2000, 43000);


ただし、これはもっと短くできる。import文を使えば、このようにパッケージを指定せずに、Flashがどのパッケージとクラスについての情報をあらかじめ持っている必要があるかをFlashに対して知らせることができる。そしてFlashはパッケージ名を毎回指定しなくともパッケージ名を自動的に推測してくれる。以下はCarクラスをインポートしてインスタンスを構築する例である。


import com.person13.Car; var car:Car = new Car("Oldsmobile", "Alero", 2000, 43000);


このほうがずっと読みやすいことに気が付くはずだ。クラス名への参照が沢山あるときは、このようにすればタイピングの時間をかなり節約できる。

*というワイルドカード記号を使って、パッケージ内の全てのファイルをインポートすることもできる。例えば、以下の文では、com.person13 パッケージの中にある全てのクラスをインポートしている。


import com.person13.*;


クラスを作成する

ActionScript 2.0のクラスに関してはこれから準備段階的なものをいくつか見て行きたい。すぐに自分のクラスを作り始めたいなら、そうしてしまってもかまわない。まずCarというクラスを作成するところから始める。以下のようなステップをたどってほしい:


1. 新規のActionScriptファイルを開く。Flash MX Professional 2004を使っているなら、IDEの中にあるActionScriptファイルエディタを使うことができる。それ以外でも、プレーンテキストのファイルを保存できるものであれば自分のお気に入りのテキストエディタを使うことができる。


2. まず最初にファイルに追加するコードは、クラス宣言である。クラス宣言をするにはclassキーワードの後にクラス名をつけて、クラス定義を中括弧で囲む。以下のコードをファイルに追加してみよう:


class com.person13.Car { }


3. 次にプロパティを5つ定義する。これらのプロパティはどれもprivateにする。最初の4つの意味は自明だろう。最後のプロパティは、メソッドの一つとして収めるインターバルメソッド用に、インターバルIDを保存するために使う。


class com.person13.Car { private var _sMake:String; private var _sModel:String; private var _nYear:Number; private var _nMiles:Number; private var _nInterval:Number; }


4. そしてコンストラクタを宣言する。この場合、コンストラクタは4つのパラメータを取得して それらの値を対応するプロパティに代入する。宣言していないプロパティを参照 しているところが2箇所あることに気付くだろう。これは、これら二つのプロパティが すぐにsetterメソッドで定義されるからだ。この場合、値が妥当であることを確認するような ロジックを採用したいという理由で、setterメソッドを設定することにしている。


class com.person13.Car { private var _sMake:String; private var _sModel:String; private var _nYear:Number; private var _nMiles:Number; private var _nInterval:Number; function Car(sMake:String, sModel:String, nYear:Number, nMiles:Number) { _sMake = sMake; _sModel = sModel; year = nYear; miles = nMiles; } }


5. 次に、クラスにメソッドをいくつか宣言する。ここでは、drive()という名前のpublicメソッドを一つ作成する。それから、increment()というprivateメソッドも作成する。一度drive()メソッドが一時間あたりの有効なマイル数を表すパラメータで呼び出されると、increment()メソッドはある間隔(interval)毎に呼び出されることになる。


6. 残りのステップでは、以下のコードで示されているように、getterメソッドとsetterメソッドを定義する:


class com.person13.Car { private var _sMake:String; private var _sModel:String; private var _nYear:Number; private var _nMiles:Number; private var _nInterval:Number; function Car(sMake:String, sModel:String, nYear:Number, nMiles:Number) { _sMake = sMake; _sModel = sModel; year = nYear; miles = nMiles; } public function get make():String { return _sMake; } public function get model():String { return _sModel; } public function get year():Number { return _nYear; } public function set year(nYear:Number):Void { if(nYear >= 1886) { _nYear = nYear; } else { _nYear = 1886; } } public function get miles():Number { return _nMiles; } public function set miles(nMiles:Number):Void { if(nMiles >= 0) { _nMiles = nMiles; } else { _nMiles = 0; } } public function drive(nMPH:Number):Void { if(nMPH == null || nMPH <= 0) { clearInterval(_nInterval); } else { _nInterval = setInterval(this, "increment", 1000, nMPH); } } private function increment(nMPH:Number):Void { _nMiles += nMPH; } }


7. まだやっていなければ、com/person13ディレクトリを自分のFlashのクラスパス内に作成する。例えば、自分のclasspathがD:\ActionScriptClassesというパスを含んでいるなら、作成したディレクトリがD:\ActionScriptClasses\com\person13であることを確認する。


8. ActionScriptクラスファイルを、com/person13ディレクトリにCar.asとして保存する。


9. 新規のFlash document(.fla)を開く。


10. メインタイムラインの第一フレームに以下のActionScriptコードを追加する:


import com.person13.Car; // 最初は、Carオブジェクトのmilesプロパティの値を // 表示する関数 function displayMileage(carObj:Car):Void { trace(carObj.miles); } // Carオブジェクトを作成する var car:Car = new Car("Oldsmobile", "Alero", 2000, 43000); // 車に対して時速65マイルで走り始めるように伝える // (US以外の人達は、自分でキロメートルに変換しないと // いけないかも! ;) ) car.drive(65); // Carオブジェクトの走行マイル数(mileage)が継続的に表示されるように // intervalを設定する
setInterval(displayMileage, 100, car);


11. ムービーをテストする

車の走行マイル数が出力パネルに表示されているのがわかるはずだ。だいたい一秒あたり65がインクリメントされているはずである。

結び

この記事では、ActionScript 2.0のクラスについて基本的なところに触れてみた。まだクラスの継承やインタフェースのimplementについての詳細にはふれていない。この記事はもう長くなりすぎたので、それらのトピックは3番目の記事のために取っておくことにする。読んでくれてありがとう。


元URLはhttp://www.person13.com/articles/as2primerparttwo/です。
日本語訳は、原著者であるJoey Lott氏の許可を得てFACEs Projectが行いました。


PART1 | TOP | PART3