オブジェクト指向プログラミングでは、開発者は「アプリケーション アーキテクチャ」という用語を使用します。 これは巧みな表現です。 ユーザはプロジェクトに建築家としてアプローチでき、オブジェクト指向の原則を基本構成要素として使用してコードを構築できます。 アプリケーションを開発する際、コードモジュールをアプリケーションの基礎を形成する設計図として考えることができます。 同じような構築物を作成するために1つの設計図を繰り返し使用でき、機能をアーカイブするために必要に応じてコードを再利用できます。

クラス概念は、すべてのオブジェクト指向コード開発の中心です。 オブジェクト指向プログラミング(OOP)についての知識がない場合でも、この記事によりActionScript 3.0クラスの記述を始めることができます。 ActionScript 3.0を使用するとクラスの記述は非常に容易になります。ActionScriptまたはActionScript 3.0を初めて使用する場合、クラスを記述すると管理およびメンテナンスが容易なプロジェクトの作成ができます。

この記事で説明されている概念により、Flashの手続き型コードおよびタイムライン関数を超えた、移植性および再利用性の高いコードの記述が可能になります。

クラスとは?

クラスとは、作成される任意の数のインスタンスの設計図を提供する関数(この記事ではメソッドと呼ばれます)の集合体です。クラスインスタンスの変数(OOP用語ではプロパティ)を変更、またはメソッドに対する引数として異なる値を渡すことにより、同じ基礎のクラスでも異なる結果になることがあります。

クラスを理解する別の方法は、Flashオーサリング環境で実行されたタスクを比較することです。ActionScriptクラスはプログラムで作成されますが、アセットを読み込み、ライブラリパネルのシンボルおよびステージ上のシンボルコピー(インスタンス)で作業をするという概念に基本的に類似しています。ステージ上のシンボルインスタンスは、クラスインスタンスに類似しています。ステージ上の異なるインスタンスは、同じシンボルからにもかかわらず、表示(色、アルファ透明度、回転など)に影響する異なるプロパティ設定を持っています。

クラスが非常に高性能である理由の1つは、同じオブジェクトから複数のインスタンス(表示および動作が異なる)を作成する能力です。開発者としてオブジェクトの表示および動作を完全に制御できるため、ActionScriptクラスはライブラリのシンボルよりも高性能です。ActionScript 3.0を使用すると、Flashオーサリングインターフェイスを通じてアクセスできないプロパティおよびメソッドにもアクセスできます。さらにActionScriptクラスは、タイムラインベースアニメーションの範囲外にあるオブジェクトを、実行中に動的にアニメーション化することができます。最後に、独自のActionScriptクラスを記述すると、作成した機能を用途を変えて利用できるため再利用性を促進できます。

このクラスがコードでどのように表示されるのかを見てみましょう。

Brick.as

package com.adobe.ooas3 { public class Brick { public var color:String = "red"; public function Brick() { trace("new "+ color +" brick created"); } } }

上記のBrick.asコードは、ActionScript 3.0クラスの最も基本的な実装を示しています。このクラスは、1つのメソッドおよびプロパティのみを保持します。コードのラインをそれぞれ見ていくと、以下の点が明らかになります。

  • まず、パッケージが定義されます。パッケージにより、ハードドライブ上のフォルダにあるコードを構築し、クラス名の競合を防ぐことができます。この例では、クラスはBrick.as(大文字と小文字の区別のあるクラス名)として「ooas3」という名前のフォルダ内に保存され、その後「com」と呼ばれるフォルダに含まれている「adobe」フォルダに保管されます。

    規則では、パッケージ名は通常プロジェクトのドメイン名の逆で、その後にプロジェクト名が続きます。これによりパッケージ名は一意となり、他のプロジェクトのクラスとの競合の危険性はありません。

  • クラスは定義され、public(アクセス修飾子については後述)として設定されます。この例では、クラスは「Brick」と命名されます。
  • コードの次のラインは、クラスで使用されるString型のパブリックプロパティ「カラー」を宣言します。カラーは赤に設定されます。カプセル化についての説明の際に、クラスプロパティのより効率的な作業方法についても説明します。
  • 最後にBrickメソッドが定義されます。これはただのメソッドではないことに注意してください。すべてのクラスにはコンストラクタがあります。これはクラスの新しいインスタンスが作成されると自動的に呼び出されるメソッドです。

    コンストラクタメソッドは、その中で定義されるクラスと常に同じ名前を持つため、容易に認識できます。これを理解していると、BrickクラスではBrickメソッドがコンストラクタであることがすぐにわかります。

    メソッドの内部で、出力パネルに「new red brick created」というメッセージがトレースされます。traceステートメントは、デフォルト値「赤」で定義された変数カラーの値を組み込みます。

このクラスを迅速にテストするには、Flash CS3 Professionalを起動し、新しい空白のActionScript 3.0 FLAを作成し、メインタイムラインの最初のキーフレームに以下のコード行を記述します。

import com.adobe.ooas3.Brick; var firstBrick:Brick = new Brick();

ムービープレビュー(制御/ムービープレビューを選択)を実行する場合、出力パネルに「new red brick created」(図1を参照)と表示されます。

出力パネルにトレースされたメッセージは、ActionScript 3.0クラスが正常に機能していることを意味します。今度はクラスを使用して、さらに高度な操作を実行してみましょう。

基本的なOOP概念:継承とコンポジション

OOPの基本には、いくつかの概念があります。この記事では最も重要な概念である継承、カプセル化およびポリモーフィズムについて説明します。また関連するいくつかの項目について説明し、これらの概念を関連付けられるようにします。

間違いなく、継承はOOPの概念の中でも最もよく知られています。継承は、プロパティおよびメソッドを継承し、既存のクラスの機能を新しいクラスにおいて拡張する能力として定義できます。

将来を考え、以前に作成した「Brick」クラスを拡張した新しい「Wall」クラスの作成を考慮してください。ただし、これは継承の動作ではありません。

レンガ(Brick)と壁(Wall)のクラスの関係を考えると、コード化する最良の方法は継承ではなくコンポジションです。

クラスの関係が継承を保証するかコンポジションを保証するかによっておよそ決定されます。クラスAがクラスB「である」場合は、継承です。クラスA内にクラスB「がある」場合は、コンポジションです。

以下は継承の例です。

  • 猫は動物「である」。
  • エンジニアは従業員「である」。
  • ラグビーはスポーツ「である」。

以下はコンポジションの例です。

  • 壁にはレンガ「がある」。
  • コンピュータにはキーボード「がある」。
  • 学校には先生「がいる」。

それでは、継承とコンポジションの実装の違いはなんでしょうか。比較をするために、まず継承から説明しましょう。

Animal.as

package com.adobe.ooas3 { public class Animal { public var furry:Boolean; public var domestic:Boolean; public function Animal() { trace("new animal created"); } } }

Animal.asコードは基本Animalクラスで、Catクラスの継承を使用して拡張します。

Cat.as

package com.adobe.ooas3 { public class Cat extends Animal { public var family:String; public function Cat() { furry = true; domestic = true; family = "feline"; } } }

Catクラスでは、コンストラクタが3つの異なるプロパティに値を割り当てます。注意してみると、これらのプロパティのうち1つ(family)のみがCatクラスで定義されていることがわかります。他のプロパティ(furryおよびdomestic)はAnimal基本クラスからのものです。

この例は実際的ではありませんが、クラス継承によって既存の機能を構築し、プロジェクトを開発する際に使用する新しい設計図を作成する方法を示しています。

6つのCatを作成する場合、汎用Animalクラスを使用し各インスタンスごとにプロパティを何度も定義する代わりに、すでにすべてのプロパティが設定されているCatクラスをインスタンス化することにより実行できます。

ActionScript 3.0の新しい機能は、拡張したクラスで定義されたメソッドを上書きする際のoverrideキーワードです。この便利な機能により、それぞれ拡張するクラス間のメソッドでの名前の重複を避けることができます。

一方、コンポジションには、extendsキーワードのような正式なシンタックスがありません。コンポジションは、使用するクラスの独自のインスタンスを単にインスタンス化します。

以前に作成したBrickクラスを例にとります。次の例では、コンポジションを使用してBrickクラスのインスタンスをインスタンス化するWallクラスを作成します。

Wall.as

package com.adobe.ooas3 { import com.adobe.ooas3.Brick; public class Wall { public var wallWidth:uint; public var wallHeight:uint; public function Wall(w:uint, h:uint) { wallWidth = w; wallHeight = h; build(); } public function build():void { for(var i:uint=0; i<wallHeight; i++) { for(var j:uint=0; j<wallWidth; j++) { var brick:Brick = new Brick(); } } } } }

上記のコードでは、Wallクラスはコンストラクタに渡された2つの引数を受け入れ、作成する壁のレンガの幅と高さを定義します。

空白FLAファイルのメインタイムラインでインスタンス化して、クラスのテストを実行してみましょう。

import com.adobe.ooas3.Wall; var myWall:Wall = new Wall(4,4);

ムービープレビュー(制御/ムービープレビュー)を実行する場合、出力パネルに表示されるtraceステートメントに対応して、16のBrickインスタンスが作成され、4×4の壁が作成されます(図2を参照)。

継承およびコンポジションクラスの関係の違いは別にして(前述のとおり)、コンポジションには実行時に他のクラスに機能を追加できるという利点があります。コンポジションはクラスインスタンスの作成および廃棄を制御します。継承ではクラスの関係はコードがコンパイルされる際に、固定され定義されます。

カプセル化

OOPの他の重要な概念であるカプセル化について説明します。カプセル化の基本的な概念は、クラスが外部に公開するメソッドおよびプロパティに関連します。

今までは、メソッドおよびプロパティをpublicとして設定しましたが、それが本当に最良の方法でしょうか?

コードを安定させる場合、およびバグやエラーの発生しにくいプロジェクトを開発する場合、他のクラスがコードを操作する方法を制限する必要があります。

重要なのは、クラスの設定に必要なメソッドおよびプロパティのみを利用可能にし、他へのアクセスを制限することです。この方法を使用すると、クラスの操作に問題が発生した場合、コード内でデバッグするための場所の数が制限されます。

ActionScript 3.0は、メソッドおよびプロパティへのアクセス修飾子として、以下のキーワードを含みます。

  • public:どこからでもアクセスできます。
  • private:その独自のクラスのみからアクセスできます。
  • protected:その独自のクラスおよびサブクラスのみからアクセスできます。
  • internal:同じパッケージのすべてのクラスからアクセスできます。

この概念を実践してみましょう。以下の例を見てください。

Person.as

package com.adobe.ooas3 { public class Person { private var _age:Number; public function get age():Number { return _age; } public function set age(val:Number):Boolean { if(_age < 0) return false; _age = val; return true; } } }

上記のコード例では、Number型の_ageプライベートプロパティを持つPersonクラスを示しています。年齢を設定できるとしても、ここでは公開プロパティは使用しません。その代わりgetter/setterメソッドを使用して、年齢をルーティングします。

Getter/setterメソッドは(以前の例で実装したとおり)プロパティのように表示されますが、メソッドのように動作します。

ageプロパティを設定すると、検証後に_ageプライベートプロパティに値を割り当てるage setterメソッドが呼び出されます。ご承知の通り、この場合年齢は負の値ではありえません。値が有効な場合、setterメソッドはtrueまたはfalseを返します。

この方法の最大の利点は、年齢値は常にsetter関数を通じてルーティングされるため、ageプロパティが設定されるごとに、検証が実行されることです。ageプロパティがpublicに設定された場合、ageプロパティを使用するクラスの各メソッドは、現在値が有効かどうかを最初に確認する必要があります。

ポリモーフィズム

この記事で説明する最後の概念は、ポリモーフィズムです。ポリモーフィズムの概念は、異なるクラスが同じメソッド名を実装するということです。

これは非常に単純な概念ですが、ポリモーフィズムには重要な点があります。最初の利点は、実行時にクラスを置き換え可能にすることです。特定のクラスの特定のメソッド名に対するハードコーディングされた参照はありません。

例えば、TeacherクラスおよびStudentクラスがあると仮定しましょう。Teacherクラスにはteachメソッド、Studentクラスにはstudyメソッドを実装できますが、ポリモーフィズムでは2つのクラスがどちらも作業メソッドを実装できるようにコードを記述することができます。TeacherおよびStudentクラスは、明らかに異なる作業メソッドが実装されていますが(teachおよび他のstudy)、共有汎用メソッド名を使用してアクセスできる単一インターフェイスを作成します。

Teacher.as

package com.adobe.ooas3 { public class Teacher { public function work():void { trace("I am teaching"); } } } Student.as package com.adobe.ooas3 { public class Student { public function work():void { trace("I am studying"); } } }

TeacherやStudentクラスのインスタンスを渡すクラスは、teacherやstudentインスタンス(または同じメソッドを実装する他のクラス)を決定するための型チェックを実行する必要はありませんが、作業メソッドを直接呼び出します。

インターフェイスを使用してクラス間にポリモーフィズムを強制できます。インターフェイスは一連のメソッドを定義する点でクラスに類似していますが、実装がないのでクラスとは異なります。インターフェイスは、クラスの有効化のために実装する必要のあるメソッドの「契約」を定義します。

以下はIWorkと呼ばれるインターフェイスの例です。

IWork.as

package com.adobe.ooas3 { public interface IWork { function work():void; } }

上記のコードからも分かるように、インターフェイスは他のクラスとよく似ています。しかしいくつか異なる点があります。大多数の開発者は、大文字のIで始まるように(オプションですが、一般的なインターフェイスの命名規則です)インターフェイスに名前を付けます。また、classキーワードの代わりに、インターフェイスはinterfaceキーワードを使用します。さらに、コードを解析すると作業メソッドのコードがあるべきセクションで、メソッドの署名のみが定義されることがわかります。

上記のインターフェイスでは、インターフェイスを実装するクラスに、戻り値タイプvoidを持つworkと呼ばれるメソッドがあることが必要です。

以下は、TeacherおよびStudentクラスがこのインターフェイスを実装する方法です。

Teacher.as

package com.adobe.ooas3 { public class Teacher implements IWork { public function work():void { trace("I am teaching"); } } }

Student.as

package com.adobe.ooas3 { public class Student implements IWork { public function work():void { trace("I am studying"); } } }

これは簡単です。implementsキーワードを追加するだけで、作業メソッドの実装を必要とするようにTeacherおよびStudentクラスの両方をセットアップできます。これら2つのクラスのいずれかから作業メソッドを削除または名前変更する場合、コンパイル時エラーメッセージを受信します。

クラスに一般的なインターフェイスを実装させることにより、インターフェイスをデータ型として使用できます。以下の例を見てみましょう。

Supervisor.as

package com.adobe.ooas3 { public class Supervisor { public function Supervisor(worker:IWork) { worker.work(); } } }

上記の例には、IWorkインターフェイスを実装するクラスのインスタンスを渡すことのできるSupervisorクラスがあります。この方法では、インターフェイスはデータ型として使用されます。

ActionScriptコンパイラは、このIWorkインターフェイスを実装するクラスインスタンスが作業メソッドを定義することを認識しています。したがって、コードがコンパイルされる際に未定義のメソッドがあっても問題にはなりません。

Flash CS3 Professionalの空白FLAのメインタイムラインの最初のフレームに以下のコードを貼り付けると、Supervisorクラスをテストすることができます。

import com.adobe.ooas3.*; var supervisor1:Supervisor = new Supervisor(new Teacher()); var supervisor2:Supervisor = new Supervisor(new Student());

ムービープレビューを実行する場合(制御/ムービープレビュー)、出力パネルに2行が表示されます。最初の行には「I'm teaching」、2行目には「I'm studying」と表示されます(図3を参照)。これらのtraceステートメントは、Supervisorコンストラクタに新しいteacherおよびstudentインスタンスを渡すことによる予測と一致します。

型キャスト

ここで、インターフェイスで定義されていない特定のクラスに対応するTeacherまたはStudent(作業メソッド以外)メソッドやプロパティにアクセスしようとすると何が起こるのか、という疑問が生じます。

Supervisorクラスは、コンストラクタに渡されるインスタンスのIWorkデータ型を使用するので、他のメソッドを呼び出す場合でもコンパイラにはそのメソッドが実装されているかを認識する方法がありません。コンパイラはエラーを報告します。

型キャストを使用し、汎用IWorkデータ型からのインスタンスをTeacherまたはStudentインスタンスに変換することにより、この問題に対処することができます。

これは、以下のようにisおよびasキーワードを使用することにより実現します。

package com.adobe.ooas3 { public class Supervisor { public function Supervisor(inst:IWork) { if(inst is Teacher) { var teacher:Teacher = inst as Teacher; trace(teacher.tenure); } if(inst is Student) { var student:Student = inst as Student; trace(student.averageGrade); } } } }

上記のコードでは、コンストラクタに渡された作業者インスタンスが、特定のTeacherまたはStudentタイプに対応するものかどうかがisキーワードによって検証されます。

asキーワードを使用するteacherインスタンスの場合、インスタンスをその特定クラスに型キャストし、その特定のメソッドおよびプロパティにアクセスできます。この場合、Teacherクラスに設定されたBoolean tenureプロパティを持つことができます。

studentインスタンスの場合も同様です。isキーワードがstudentとの作業を確認すると、汎用IWorkインスタンスをstudentインスタンスに型キャストし、averageGradeプロパティにアクセスできます。

これは非常に便利なビヘイビアです。任意数のデータ型を受け入れる必要のある一連のクラスがある場合、一般的なインターフェイスを実装する限り、このようなポリモーフィズムの使用はプロジェクトにとって利点となります。インターフェイスを実装するクラスの特定メソッド実装が必要な場合、型キャストが有効です。

次のステップ

この記事では、ActionScript 3.0のオブジェクト指向プログラミングの基本を説明し、クラスの概念と、継承、カプセル化、ポリモーフィズムといったアプリケーション基本構成要素を取り上げました。

サブクラス化またはコンポジションを使用したクラスの拡張を学習しました。さらに、アクセス修飾子の使用方法、およびgetter/setterメソッドを使用したAPIの提供によりアクセスを制限する方法も学習しました。最後に、複数クラスがインターフェイスを使用してメソッドの同じセットを実装するように強制する方法、および型キャストにより汎用インスタンスを特定実装に変換する方法も学習しました。

これはすばらしいことです。ここまで学習すると、これらの新しい概念を実践し、ActionScript 3.0プロジェクトのオブジェクト指向プログラミングを利用して、成果を得ることができます。

詳細に関する記事およびチュートリアルについては、ActionScriptテクノロジセンターを確認し、ActionScript 3.0での作業についての詳細な知識を入手してください。

ActionScript 3.0でFlashアプリケーションを開発する際のクラスおよびプログラミングのヒントに関する具体的な情報をまだ入手していない場合は、Flashクイックスタートを参照して入手してください。