BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ アーティクル JavaプログラマのためのActionScript 3

JavaプログラマのためのActionScript 3

現実と向き合ってみましょう。クライアントは、Javaプログラマーにとって親しみやすい場所ではありません。applet、 Swing、JavaFXによるクライアントのJavaテクノロジーは、ある程度の成功をおさめました。JavaScriptは、その名前にも関らずほとんどがJava言語らしくありません。さて、Adobe Flashは、まるでJavaScriptのようですか? 違いますか? 2、3年前は、FlashはJavaScriptのようだったことは事実だったかもしれません。しかし、ActionScript 3の登場で、その多くが変わりました。そして、あなたはその多くに気づくでしょう。

第一に、ActionScript(Adobe FlexとFlashのプログラミング言語)は、強い型づけ言語です。クラスやインターフェースを含む、第一級のオブジェクト指向でもあります。それは、Javaには無いものを追加でもっています。特に、プロパティのためのget と set ファンクションや、ECMAScript for XML (E4X)と呼ばれる言語拡張は、どんなXMLドキュメントでも、通常のオブジェクトのように.(ドット)オペレータによって参照可能なオブジェクトに変換します。

本稿では、ActionScript 3の基礎を通じて、あなたが使い慣れているJava環境とどのくらい違うのかを説明します。最後には、全ての先入観が取り除かれ、それで楽しむことにいくらかの関心を持つでしょう。Flex、Flash、ActionScriptの素晴らしい点の一つは、それらが無料で利用できるということです。始めるには、単純にAdobe Flex Builder 3(リンク)をダウンロードします。Flex Builderは、洗練された統合開発環境(IDE)で、無料のアプリケーションではありません。しかし、Flexのソフトウェア開発キット(SDK)で、Flashのアプリケーションをビルドすることができます。

本稿を読む際の、言語純粋主義者への警告です。私は、言語の教祖ではありません。したがって、ある言語の詳細についてきれいごとを言うかもしれません。また、私は本稿の中でActionScript 3のすべてを説明するつもりもありません。必要であれば、ActionScript 3に関する多くの良書があります。私ができることは、言語に対する感触を与えることです。では、始めましょう。

クラスとインターフェース

ちょうどJavaと同じように、ActionScript 3ではすべてのものがオブジェクトです。整数のようないくつかのプリミティブ型はあるものの、それ以外については全てがオブジェクトです。Javaと同様に、com.jherrington.animalsのような名前空間とパッケージがあります。この場合は、company / jack herrington / animal クラスを意味します。クラスをデフォルトの名前空間に置くことも可能ですが、名前空間を管理する方が良いです。

クラスを定義するには、Javaと同様にキーワードclassを使用します。以下は実例です。

package com.jherrington.animals
 {
 	public class Animal
 	{
 		public function Animal()
 		{
 		}
 	}
 }

この場合は、何もしないコンストラクタでAnimalクラスを定義しています。

以下で示すように、2、3のメンバ変数を加えることで、とても容易にコンストラクタを洗練することができます。

package com.jherrington.animals
 {
 	public class Animal
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private function Animal( _name:String, _age:int = 30 )
 		{
 			name = _name;
 			age = _age;
 		}
 	}
 }

ここでは、私はAnimalオブジェクトが2つのメンバ変数を持つことを定めています。まず、nameはパブリックな文字列で、ageはプライベートな整数です(おそらく、動物は年齢を言うのをためらっているのでしょう)。そのコンストラクタは、一つ、あるいは二つの値をとります。nameだけのときと、nameとageのときのいずれかです。関数宣言の中でデフォルト値を追加することで、引数に対するデフォルト値を提供することができます。

このコードで注目すべき点は、型定義がJavaとは逆であることです。Javaでは型が先にきますが、 ActionScriptでは後にきます。これは、強い型づけがActionScriptへのアドオンであるからです。したがって、従来の型づけのないコードをサポートをするために、変数名の後に型がきます。

いくつかメソッドを追加することで、サンプルを拡張してみましょう。

package com.jherrington.animals
 {
 	import flash.geom.Point;

 	public class Animal
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private var location:Point = new Point(0,0);

 		public function Animal( _name:String, _age:int = 30 )
 		{
 			name = _name;
 			age = _age;
 		}

 		public function moveTo( x:int, y:int ) : void {
 			location.x = x;
 			location.y = y;
 		}

 		public function getLocation( ) : Point {
 			return location;
 		}
 	}
 }

ここで分かることは、別のプライベートなPoint型のメンバ変数locationを追加したことです。それは、Flashのgeometryパッケージからインポートしたものです。そして、locationと共に機能する2つのメソッドを追加しています。moveToはanimalを移動し、getLocationは現在のlocationを返します。

さて、Javaのやり方と似た値のsetとgetです。ActionScriptでそれをするのは、より簡潔で以下のコードのようになります。

package com.jherrington.animals
{
 	import flash.geom.Point;

 	public class Animal
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private var myLocation:Point = new Point(0,0);

 		public function Animal( _name:String, _age:int = 30 )
 		{
 			name = _name;
 			age = _age;
 		}

 		public function set location( pt:Point ) : void {
 			myLocation = pt;
 		}

 		public function get location( ) : Point {
 			return myLocation;
 		}
 	}
 }

ここでは、get と set関数を使用し、クライアントのコードによってメンバ変数のlocationの値を取得・設定するときに呼び出されます。クライアントでは、location変数は、通常のメンバ変数のように見えます。しかし、あなたが望むメンバー変数の設定を処理するためのコードであれば何でも、set で処理することが可能です。同様にして、変数のgetを扱うことができます。

あなたはこれをどのように使いますか? locationが変わったときをトリガーとしてイベントを追加することもできます。以下のコードを見てください。

package com.jherrington.animals
{
  	import flash.events.Event;
 	import flash.events.EventDispatcher;
 	import flash.geom.Point;

 	public class Animal extends EventDispatcher
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private var myLocation:Point = new Point(0,0);

 		public function Animal( _name:String, _age:int = 30 )

 			name = _name;
 			age = _age;
 		}

 		public function set location ( pt:Point ) : void {
 			myLocation = pt;
 			dispatchEvent( new Event( Event.CHANGE ) );
 		}

 		public function get location( ) : Point {
 			return myLocation;
 		}
 	}
 }

さて、私はAnimalクラスにイベントディスパッチャーを指定しました。それは、クライアントがイベントに対してリスンすることができるオブジェクトです。ここでは、locationが変更したときに新しいイベントをディスパッチしています。

以下では、animalを生成し、changeイベントの監視に自身を設定しています。そして、そのlocationを変更します。

	var a:Animal = new Animal();
 	a.addEventListener(Event.CHANGE, function( event:Event ) : void {
 		trace( "The animal has moved!" );
 	} );
 	a.location = new Point( 10, 20 );

このコードは、animalが変更したときにトレースメッセージを出力しています。ActionScriptで望むどんな型のメッセージでも明示することができます。大抵のクラスはEventDispatcherで、リスナーを追加可能なイベントをもっています。

インターフェース

Javaのように、ActionScript 3言語ではインターフェースの構築とそれらをクラスで実装することをサポートしています。下記に示すインターフェースは、私たちがAnimalクラスから作成する例です。

package com.jherrington.animals
 {
 	import flash.geom.Point;

 	public interface IAnimal
 	{
 		function get name() : String;
 		function set name( n:String ) : void;

 		function get location() : Point;
 		function set location( pt:Point ) : void;
 	}
 }

このケースでは、setとgetの両方を持ったインターフェースに対し、2つのメンバ変数を定義しています。そう、ActionScriptのインターフェースでは、メソッドとメンバ変数を定義することができます。いけてると思いませんか?

インターフェースを実装するために、私はAnimalクラスに若干の変更をおこないました。下記のコードで、それを見ることができます。

package com.jherrington.animals
 {
 	import flash.events.Event;
 	import flash.events.EventDispatcher;
 	import flash.geom.Point;

 	public class Animal extends EventDispatcher implements IAnimal
 	{
 		private var myName:String = "";

 		public function get name() : String
 		{
 			return myName;
 		}
 		public function set name( n:String ) : void
 		{
 			myName = n;
 			dispatchEvent( new Event( Event.CHANGE ) );
 		}
 		private var myLocation:Point = new Point(0,0);

 		public function set location ( pt:Point ) : void {
 			myLocation = pt;
 			dispatchEvent( new Event( Event.CHANGE ) );
 		}

 		public function get location( ) : Point {
 			return myLocation;
 		}

 		public function Animal( _name:String )
 		{
 			name = _name;
 		}
 	}
 }

もちろん、このクラス特有の変数やメソッドを追加したり、IAnimalインターフェースに加えて他のインターフェースを実装することもできます。一方、Javaでは一つの基底クラスからのみ継承が可能です。

StaticとConstant

ActionScript 3では、staticなメソッドだけでなく、コンスタント値やstaticなメンバ変数をサポートします。コンスタントは定義が簡単で、以下のコードのようになります。

		public const MINIMUM_AGE:int = 0;
  		public const MAXIMUM_AGE:int = 2000;

コンスタントはあなたが望む全ての型で可能ですが、それらはコンパイル時に定義される必要があります。また、スコープが必要であれば、protectedやprivateも可能です。

staticな関数を説明するために、Animal クラスのファクトリメソッドを示します。

		public static function buildAnimal( n:String ) : IAnimal {
 			return new Animal( n );
 		}

staticなメソッドを利用するもう一つの方法は、シングルトンパターンです。下記は、Animal クラスに対するシングルトンなfactory クラスの例です。

package com.jherrington.animals
 {
 	public class AnimalFactory
 	{
 		private static var _factory:AnimalFactory = new AnimalFactory();

 		public static function get instance() : AnimalFactory {
 			return _factory;
 		}

 		public function build( n:String ) : Animal {
 			return new Animal( n );
 		}
 	}
 }

それを呼び出すために、単一のfactory オブジェクトを得るための instance メンバ変数を利用します。

private var b:Animal = AnimalFactory.instance.build( "Russell" );

ここでは、Russellという名前の新たなanimalオブジェクトを生成するために、シングルトンなファクトリオブジェクトを使用しています。

継承

継承を説明するために、私は3つのインターフェースとクラスを示します。第一のインターフェースは、先に示したIAnimal クラスです。第二は、そのAnimal クラスです。第3は、メソッドをオーバーライドしたDog という名の導出クラスです。

インターフェースのIAnimalは、以下のとおりです。

	public interface IAnimal
 	{
 		function get name() : String;
 		function set name( n:String ) : void;

 		function move( x:int, y:int ) : void;
 	}

インターフェースをname メンバ変数とmove()メソッドだけにすることで、少し単純化しました。そのインターフェースの初めの実装は、Animalクラスです。

public class Animal extends EventDispatcher implements IAnimal
 {
 	private var myName:String = "";

 	public function get name() : String
 	{
 		return myName;
 	}
 	public function set name( n:String ) : void
 	{
 		myName = n;
 		dispatchEvent( new Event( Event.CHANGE ) );
 	}

 	public function Animal( _name:String )
 	{
 		name = _name;
 	}

 	public virtual  function move( x:int, y:int ) : void
 	{
 	}
 }

そして、Dogクラスは Animal クラスをもとに、自身のコンストラクタとmove()メソッドをオーバーライドすることによって作成されます。

public class Dog extends Animal
 {
 	public function Dog(_name:String)
 	{
 		super(_name);
 	}

 	public override function move( x:int, y:int ) : void
 	{
 		trace( 'Moving to '+x+', '+y );
 	}
 }

これは非常にJavaコードに似ているので、ActionScriptでオブジェクト指向設計を実装している中で、実際にホームグラウンドにいるように感じるでしょう。

演算子と条件式

ActionScriptの演算子は、あなたがJavaで見ているものと全く同じです。同様に、算術演算子とブール演算子も同じです。

	var a:int = 5;
 	var b:int = 6;
 	var c:int = a * b;
 	c *= 10;
 	var d:Boolean = ( c > 10 );
 	var e:int = d ? 10 : 20;

これらの例は、いくつかの異なる演算子を示しています。ActionScriptとJavaの間のこれらの例の唯一の違いは、変数を定めるための構文です。

演算子のように、条件式も両者の言語間で全く同じように機能します。以下が例です。

	if ( a > 10 ) {
 		trace( 'low' );
 	}
 	else if ( a > 20 ) {
 		trace( 'high' );
 	}
 	else {
 		threw new Exception( "Strange value" );
 	}

条件式の構文と例外をスローする方法の両方を示しています。例外のハンドリングも、Javaと全く同じです。自身の例外型を定義することができるし、単純に、標準のExceptionクラスを使用することもできます。

trycatch、finallyの構文は、以下の例のようになります。

	try
 	{
 		location = new Point( -10, 10 );
 	}
 	catch( Exception e )
 	{
 		trace( e.toString() );
 	}
 	finally
 	{
 		location = null;
 	}

このコードでは、locationをセットしようとして問題が発生したらトレースログを出力しています。いずれにせよ、最終的にlocationにはnullがセットされます。

イテレータ

ActionScript 3では、強く型付けされたコンテナを持っていません。しかし、配列とハッシュテーブルを扱うことは簡単です。以下は、配列の繰り返しのforループを使用した例です。

	var values:Array = new [ 1, 2, 5 ];
 	for( var i:int = 0; i < values.length; i++ )
 		trace( values[i] );

しかし、これは本当に、あなたがActionScriptで配列を繰り返したい方法ではありません。次のサンプルで示すように、ベストな方法は、for each構文を使用することです。

	var values:Array = new [ 1, 2, 5 ];
 	for each ( var i:int in values )
 		trace( i );

このコードは、配列のそれぞれの要素を繰り返し、それぞれの要素に i の値をセットしています。

ハッシュテーブルを作成するためには、ActionScriptでは基底のObject型を使用します。

	var params:Object = { first:'Jack', last:'Herrington' };
 	for( var key:String in params )
 		trace( key+' = '+params[key] );

JavaScriptの中のActionScriptの由来するところは、基底のobject型が、ハッシュテーブルを簡単に使用することができるように、スロットベースのコンテナであることです。

正規表現

正規表現は、ActionScriptの基本的な構文となっています。例えば、以下のコードのようになります。

	if ( name.search( /jack/i ) )
 	{
 		trace('hello jack');
 	}

単純に文字列のチェックをおこないます。

このコードでは、splitメソッドを実行するために正規表現を使用しています。:

	var values:String = "1,2,3";
 	for each( var val:String in values.split(/,/) ) {
 		trace( val );
 	}

正規表現を核となる構文に組み込む必要があるのかについては、疑問の余地があります。Javaの設計者たちは、これらの表現は外部ライブラリにあるべきだと考えました。しかし、私はそれらがActionScriptにあり統合されていることで、十分に役に立つと思います。

E4X

XMLは十分広く利用されているので、ActionScriptではそれをサポートし、言語構文としてきちんと取り込んでいます。あなたがXMLジャンキーなら、これを大好きになるでしょう。下記を見てください。

var myData:XML = <names>
	<name>Jack</name>
	<name>Oso</name>
	<name>Sadie</name>
</names>;
	for each ( var name:XML in myData..name ) {
		trace( name.toString() );
}

このコードは、XMLドキュメントを定義しています。そして、それを検索し、すべてのタグを出力しています。

次のちょっとしたコードも、 タグだが、type がdogであるものだけを取得しています。

var myData:XML = <names>
	<name type="person">Jack</name>
	<name type="dog">Oso</name>
	<name type="dog">Sadie</name>
</names>;
	for each ( var name:XML in myData..name.(@type='dog') ) {
		trace( name.toString() );
}

@構文は、XPathとXSLTと似ています。それは、XML要素ではなく属性の検索を指定するために用いられます。

E4Xは、言語への素晴らしい追加といえます。それにより、XMLパースを雑用から喜びに変えます。Webサービスでも、簡単なパースでE4X形式で返すことができます。

まとめ

Adobeは、ActionScriptで驚異的な進歩を遂げました。それは、大抵の人たちが認めている言語と比べても、はるかに洗練された言語です。私は、Adobeがおこなったことにより、Javaについて何が良くて何が悪いのかということから、いくつかの教訓を得られると思います。そして、それらをActionScript 3言語の開発に盛り込まれると思います。あなたはその結果にとても喜ぶことでしょう。

さらに学ぶために

  • ActionScriptとJava構文との類似点の詳細については、Yakov Fain氏の記事「Java 5とActionScript 3の構文を比較する」(JDJ、2006年11月12日)を読んでください。
  • JavaからActionScriptへのコンバータは、Flashコンテンツを作成するためにActionScriptよりもJavaを使用することができるオープンソースFlashからダウンロードして利用可能です。
  • あなたがActionScript、Flex、JavaとJavaScript開発の間でマイグレーションを支援するためのリソースのリストとして、RIAdobeの比較リストを参照してください。
  • Flex.orgは、Adobe Flexのすべてに対する情報源です。

 

原文はこちらです:http://www.infoq.com/articles/actionscript-java
(このArticleは2008年8月25日に原文が掲載されました)

この記事に星をつける

おすすめ度
スタイル

BT