homeへのリンクです。

flashでAmazonECS 14

2006年08月17日

類似のクラスのバリエーション(同じインターフェイスを持つクラス群)があって、それを選択的に利用するとき、クラス名による分岐が必要なる。
この場合、分岐に必要なStringとクラスの識別子を結びつけなければならない。
AS2.0では、以下のようなカスタムユーティリティクラスを作って利用していた。

import classes.util.*;
import classes.layout.*;
import classes.main.*
class LayoutConstructor{
   public function makeClass
(layouttype:String,targettimeline:MovieClip,datanum:Number,main:Main):Layout{
      var layout:Layout;
      switch(layouttype){//与えられたStringに対応するクラスを返す。
         case "gridlayout":
         layout=new GridLayout(targettimeline,datanum,main);
         break;
       }
       return layout;
   }
}

呼び出し側の例

mycons=new LayoutConstructor();
layouttype="gridlayout";//レイアウトの形式を決定する
mycons.makeClass(layouttype,mytimeline,datanum,mymain);

このような感じ。

AS3.0ではflash.utilsパッケージにgetDefinitionByName()ファンクションが準備されているので、それを利用することになる。
AS3.0リファレンス参照。
サンプルによれば、

var layout:Class = getDefinitionByName(layouttype);
new layout(mytimeline,datanum,mymain);

で良いはずなのだが、実際には少し違っている。
そのクラスが利用されることを事前に明確に予約しなければならない。

例えば、カスタムクラスのGridLayoutクラスを定義して、それをgetDefinitionByNameで利用するには、

var layouttype:String="GridLayout";
var classdef:Class=getDefinitionByName(layouttype);
var layout:Layout=new classdef();
//ラベルクラスLayoutを利用して戻り値のタイプ指定をしない。

だけでは、

ReferenceError: Error #1065: 変数 GridLayout は定義されていません。

となるので、例えば、以下のような記述を追加する必要がある。

var layouttype:String="GridLayout";
var classdef:Class=getDefinitionByName(layouttype);
var layout:GridLayout=new classdef();
//戻り値のタイプをGridLayoutと明示、固定化する。

変数layoutのタイプ指定をGridLayoutと明示することで初めて、GridLayoutクラスの利用が明示されることになり、getDefinitionByNameで利用できるようになる。

これはちょっと微妙な仕様で、おそらく、どのクラスを利用するかを可変にしたいので、わざわざストリングからクラスを生成するわけで、タイプ指定でクラスを固定しなければならないのでは意味がなくなる。

ので、例えば、

var dummy:GridLayout;//利用しない変数のタイプ指定をGridLayoutにする。
var layouttype:String="GridLayout";
var classdef:Class=getDefinitionByName(layouttype);
var layout:Layout=new classdef();

のように、無関係な部分で:GridLayoutを記述することで、GridLayoutの利用を明示して、実際の戻り値の変数のタイプ指定には幅を持たせることが出来る。

カスタムクラスの利用の予約を明示するには、変数のタイプ指定でクラス名を明記するやり方のほかに、どこかでnew GridLayout()を記述しておく、というやり方もある。

例えば、

var dummyflg:Boolean=fales;
if(dummyflg){
   new GridLayout();
}
var layouttype:String="GridLayout";
var classdef:Class=getDefinitionByName(layouttype);
var layout:Layout=new classdef();

などでも良い。

ちなみに、if(flase)としたブロックにnew GridLayout()を記述しても、絶対呼ばれないルーチンとして無視されるのでNGになる。

また、クラス名として渡すストリングは、同一パッケージ内のクラスや、import済みのパッケージ内のクラスでも、パッケージ名から全て含める必要がある。
"classes.layout.GridLayout"
のような感じ。