複数SWF間でクラスを共有させるコツ(2)
複数SWF間でクラスを共有させるコツ(1)の続きです。
親SWFのクラスを読み込まないで共有させるには
ちょっとヘンないい方ですが、ようはErrorPanelの内部的な変更が反映されないことが問題なので、ErrorPanelでない形で渡せればよい、という考え方で進めます。
方法はいくつかありますが簡単な方から紹介していきます。
ビルトインクラスとして読み込む
ビルトインクラスは、開発の都合で変更されたりしないので、どちらのSWFにも入っていても食い違いの問題が発生しません。
ErrorPanelはSpriteを継承していました。前回のグローバル変数クラスの宣言をSpriteとすると、親SWFではErrorPanelとして、(ErrorPanelを知らない)子SWFにとってはただのSpriteとして扱うということが可能になります。
public class GlobalVariables{ public static var errorPanel:Sprite; } GlobalVaribales.errorPanel = new ErrorPanel();
すでにキャストされているので、サブクラスの機能を使うことはできませんがErrorPanelを変更しても子SWFを書き出し直す必要はありません。
Classを渡す場合も同じように、生成時にSpriteとしてキャストする分にはErrorPanelを埋め込まれません。(ただし暗黙の了解の課題は残りますが)
共有用の抽象クラスとして読み込む
ビルトインクラスの場合は、拡張した機能は一切使えないので不便なことがあります。
たとえばエラーメッセージを変更ししたい場合を考えてsetMessage, getMessageを定義した共有オブジェクトを考えましょう。
共有するクラスがビルトインクラスではなくても変更がなければいいので、あらかじめ共有用の抽象的なカスタムクラスを定義してそれを継承します。
// 抽象的なクラス public class MessagePanel extends Sprite{ public function setMessage(msg:String):void { //実装はサブクラスでする } public function getMessage():String { //実装はサブクラスでする } } // 具体的なクラス public function ErrorPanel extends MessagePanel{ public var messageField:TextField; override public function setMessage(msg:String):void { // 具体的な実装 messageField.text = msg; } override public function getMessage():String { //具体的な実装 return messageField.text; } } // グローバル変数クラス public class GlobalVariables{ public static var errorPanel:MessagePanel; } //親SWF GlobalVariables.errorPanel = new ErrorPanel(); //子SWF(MessagePanelは知っているがErrorPanelは知らない) GlobalVariables.errorPanel.setMessage( "エラーです" );
こうすれば子SWFにはSprite+MessagePanelの機能までは共有され使えるようになりましたが、ErrorPanelでどう実装されたかは関係ないので、具体的な実装が変更されても再書き出しの必要はないのです。
もちろん MessagePanelのほうに変更があれば再書き出しが必要ですが、ErrorPanelをそのまま提供するよりは反映の頻度が大きくへるので、開発効率は良くなると思います。
切り分けることが分かった時点で、あらかじめどういう機能を子SWFに提供するかをきちんと考えておけばほとんど食い違いによる不具合は起こらないでしょう。
インターフェイスを使う
段階的にいろいろ紹介しましたが、必要なところだけ共有するという観点で効率のよい方法がインターフェイスという仕組みです。
インターフェイスとは一つまえの提供する機能を定義しただけの型宣言の仕組みです。 先ほどの抽象的なクラス宣言をインターフェイスに置き換えてみます。
// インターフェイス public interface IMessagePanel { function setMessage(msg:String):void; function getMessage():String; } // 具体的なクラス public function ErrorPanel implements IMessagePanel{ public var messageField:TextField; public function setMessage(msg:String):void { // 具体的な実装 messageField.text = msg; } public function getMessage():String { //具体的な実装 return messageField.text; } } // グローバル変数クラス public class GlobalVariables{ public static var errorPanel:IMessagePanel; } //親SWF GlobalVariables.errorPanel = new ErrorPanel(); //子SWF GlobalVariables.errorPanel.setMessage( "エラーです" );
なれるまでは わかりにくいかもしれませんが、子SWFにとってIMessagePanel以上の情報はしらなくてもよくなります。
その代わりSpriteかどうかはわかりませんので、Spriteなどの表示要素としても使いたい場合はインターフェイスよりも前者の抽象的なクラスを利用したほうがいいかもしれません。
とにかく変更の影響と使い勝手のバランスをかんがえて設計することが大切です。
オマケ情報
一つのクラスでインターフェイスを複数実装できるので、使う場面によっていくつかの顔をもつようにして、不要な機能を触らせない用にすることができます。
またインターフェイスの継承もできますので、IEventDispatcherのような他のインターフェイスに機能をかぶせて宣言することも可能です。(BetweenAS3のITween、IITweenなど)