2010年03月31日

OOP その5 インターフェイス

ん〜、いつになったらクラスのお勉強ができるのだろうか・・・
まだまだ意味不明な言葉だらけで、意識が朦朧としてきた(笑)

【注意】素人が迷走しながら書いてる記事なので参考にしないで下さい(苦笑)

インターフェイス


これはどうやら、「継承」と関係がある模様。
スーパークラスもポリモーフィズムも継承に関係する要素だったけど、
これらはカスタムクラスを作成する際に重要になってくるんだろうな。
でも、未だにカスタムクラスを使うようなプログラムを組んだことがないんだけどな(苦笑)
でも知ってて損はないだろうから、頑張ってみる。。。

「インターフェイス」って言葉自体は、聞いたことある。
このソフトのインターフェイスは、シンプルでかっこいいとか。
でもこのインターフェイスと、オブジェクト指向でいうインターフェイスは、少し違うみたい。
インターフェイスとは、異なる2つのモノの間を通信するための仲介役みたいなもので、やり取りする方法を定めた規格のことらしい。
これには3種類あって

「ハードウェアインターフェイス」
複数の装置間で通信するための規格

「ソフトウェアインターフェイス」
プログラム間でデータをやり取りするための規格

「ユーザーインターフェイス」
コンピュータとユーザー間で情報を表示/入力するための規格。
また、グラフィック表示やマウス操作などを用いたものを「グラフィカルユーザーインターフェイス」という。

よく耳にする「インターフェイス」は、ユーザーインターフェイスのことだったのね。
でも、ここで勉強するのは「ソフトウェアインターフェイス」になる。


さて、ここで継承をおさらい。
スーパークラスの機能をサブクラスへ引き継ぎ・追加・変更できる。
サブクラスを作成するときに、スーパークラスを既存のクラスから指定することができる。

で、ここがポイント。
「アクションスクリプトでは、指定できるスーパークラスは一つだけ」
二つ以上のスーパークラスから継承することを「多重継承」というらしいのだが、この多重継承はアクションスクリプトでは認められないとのこと。

でも、カスタムクラスでイベントリスナー使いたいんだけど、スーパークラスにはaddEventListenerメソッドがないのよ!ってな場合に、インターフェイスを使うとaddEventListenerメソッドが使えるようになる。

使えるようにするには、
1、インターフェイスを定義する
「このインターフェイスを使いますよ〜」って書くだけで、具体的な指示は書かない。

2、インターフェイスの実装
実装できるのはクラスに対してのみ。
複数のインターフェイスを実装することができる。
細かい書き方の規則があるようだが、それはまたの機会に。

3、クラスのインスタンスを生成
実際にタイムライン上で使うには、当然インスタンスを生成しなくちゃいけない。


では、インターフェイスってどんなの?ってことだが、
ActionSctipr3.0 コンポーネントリファレンスガイドを見ると
I (大文字アイ)で始まる斜体文字がインターフェイスらしい。
コンポーネントの中にあるので、探すの大変なんだけど、例に出したイベントリスナーを含むインターフェイスは
こちら

なんつーか、正直わからん(苦笑)
使ってみてはじめて理解できるのかもしれない。
ってこれでは今までと変わらないじゃないか!
前途多難だな。。。


とりあえず、結論。
・サブクラスで継承または拡張ができない場合に、インターフェイスを実装することで、そのインターフェイスに含まれるメソッドが使えるようになる。
・一つのクラスに複数のインターフェイスを実装できる。


例に出したaddEventLitenerメソッドは、EventDispatcherクラスにもある。
で、なにが違うのか調べてみた。

EventDispatcherクラスをみると、
EventDispatcher クラスは、IEventDispatcher インターフェイスを実装し、DisplayObject クラスの基本クラスです。

と書かれてある。
つまり、このクラスのaddEventListenerメソッドは、IEventDispatcherインターフェイスを実装することで使えるようにしてあるよってことだと思う。


リファレンスのインターフェイスの記事を見ると、次のように書かれてある。
インターフェイスは、関連しないオブジェクトの相互の通信を可能にするメソッド宣言の集合です。

この「相互の通信を可能にするメソッド」をインターフェイスにしているんだと思う。



posted by K at 15:03| Comment(5) | OOP | このブログの読者になる | 更新情報をチェックする

OOP その4 ポリモーフィズム ダイナミックバインディング

【注意】素人が迷走しながら書いてる記事なので参考にしないで下さい(苦笑)

ポリモーフィズム(多態性)


スーパークラスとサブクラスの関係で、同じ名前のメソッドでもオブジェクトによって処理内容を変更できる仕組みのこと。
継承で書いた「サブクラスを作成する際に、拡張(追加)とオーバーライド(変更)が出来る」このことと関係している。

CS3ドキュメンテーション 継承

上の記事からの引用
継承を使用すると、コード内で "ポリモーフィズム" を利用することもできます。
ポリモーフィズムを使用すると、異なるデータ型に適用された場合に異なる動作を実行するメソッドに単一のメソッド名を使用できます。
単純な例として、2 つのサブクラス Circle と Square を持つ Shape という名前の基本クラスがあります。
Shape クラスは、形状の面積を返す area() というメソッドを定義します。
ポリモーフィズムが実装されている場合、Circle 型および Square 型のオブジェクトで area() メソッドを呼び出して、正しい計算を行うことができます。
継承では、サブクラスが基本クラスからメソッドを継承し、再定義できるようにする、つまりオーバーライドを許可することで、ポリモーフィズムが有効になります。


なるほど!と思えたけど、取っ付き難い文章なので書き換えてみる。
Shapeクラスを拡張してareaという名前の面積を計算するメソッドを作る。
Shapeクラスをスーパークラスとした、Circleクラス(円)とSquareクラス(正方形)の二つのサブクラスを作る。
この両方にareaメソッドを継承したい場合。

円の面積の求め方は、半径×半径×円周率
正方形の面積の求め方は、辺の長さ×辺の長さ

同じareaという名前のメソッドを作るけど、Shapeクラスからそのまま継承しただけでは、間違った解になってしまうので、それぞれ違う計算方法を書かないといけない。
そこで、オーバーライド(変更)を許可して、areaメソッドを継承して、Circleクラスのareaメソッドには円の面積の求め方を書き、Squareクラスのareaメソッドには正方形の面積の求め方を書く。

まぁ、継承にもいろいろ決まりごとがあるようですが、それはまた別の機会に勉強することにします。


ダイナミックバインディング(動的型付け)


対義語で「静的型付け」というのがある。
これは「型」のお話なんだけど、どの時点で「型」が決まるかで違いがあるらしい。
んで、JAVAとかC#は「静的型付け言語」で、アクションスクリプトは「動的型付け言語」というふうに、言語によって違うらしい。
JAVAなど知ってる人は違いが解るのかもしれないけど、私は他の言語を知らないのでちょっと難しい。。。

例えば、アクションスクリプトで型指定をしていない変数hogeを作成したとする。
hoge=10;
としたら、hogeはNumber型になる。
hoge="10";
としたら、hogeはString型になる。
このように、実行した段階で型が決まることを「動的型付け」というのだと思う。
静的だと、エラーが出るってことかな?

Stringとして扱いたいのに、誤って数値として代入してしまった場合、動的だとエラーにならないので、関連プログラムを実行するまでバグに気づかない。
これが動的型付けの弱点らしい。


まぁASでもhoge:Number="10";ってするとコンパイルエラーが出るんですけどね。
おもしろいので、ついでにこんなこともしてみた。
var hoge:Number;
hoge = "10" + 10;
trace(hoge);
trace(typeof(hoge));

さて出力結果はどうだったでしょうか?

hogeの値=1010
hogeの型=number

コンパイルエラーにはならずに、値はストリングの足し算と同じ結果になって、データ型はnumberのままでした。
つまりhogeには1010という数値が入っているんですね。
じゃぁ、hoge="A"+10; としたらどうかな?

hogeの値=NaN
hogeの型=number

NaNとは、非数。つまり数にあらず(非ず)ってことだから、数値として表示できないってこと。
ちなみにNumber型のデフォルト値はNaN

これらの出力結果は、ごもっともだけど、"10"+10とか、つい、やらかしてしまうミスでもあるよね。。。
でも、こういう風にかくと、ちゃんとコンパイルエラーが出るんだよね。
var hoge:Number;
hoge = 10;
hoge += "10";

これで型指定しなかった場合は、1010のString型になっちゃう。
あるいは、hoge += Number("10"); と書いたら、値は20でNumber型になる。

だから、変数やインスタンスを生成するときは、ちゃんと型指定しようねってことなんだろうな。

あれ?なんか話が脱線してる?(笑)
いや、そうでもないか。
型指定することで、ある程度、動的型付き言語の弱点が補えるってことだよね。たぶん。


posted by K at 10:33| Comment(1) | OOP | このブログの読者になる | 更新情報をチェックする

OOP その3 インヘリタンス(継承)

【注意】素人が迷走しながら書いてる記事なので参考にしないで下さい(苦笑)


ということで、やっとオブジェクト指向プログラミング言語の3つの概念に着手です。
・インヘリタンス(継承)
・ポリモーフィズム(多態性)
・ダイナミックバインディング(動的束縛)


インヘリタンス(継承)


これは文字通り、スーパークラスからサブクラスへプロパティやメソッドが継承されるって意味なのだが、まずはスーパークラス/サブクラスって何よ?って話。

クラスとは、数あるコードを使いやすくするためにグループ化したもので、このクラスにもスーパークラスとサブクラスというものがある。
あまり例え話は好きじゃないけど・・・・
例えば、生物をクラス分けすると佐藤さんはどのクラスに属するかを検証。

佐藤さんは人間で、人間は哺乳類。
これをクラスにすると、こうなる。

スーパークラス=哺乳類
サブクラス=人間
佐藤さん=人間クラスのインスタンス

哺乳類は胎生で生まれて母乳で育てますよね。
この機能をサブクラスが、スーパークラスから継承していて、
それに人間の機能を追加したのが人間クラスになる。
そのインスタンスが佐藤さんで、人間クラスの機能を備えている。
これが継承。


で、アクションスクリプトでいうとスーパークラスってどれになるの?ってとこだけど
リファレンスみても「これがスーパークラスです」って出てこないんですよね。
で、こんな記述を発見。

ActionScript2.0 コンポーネントリファレンスより引用
Flash でのサブクラスの作成について
オブジェクト指向プログラミングでは、サブクラスは、スーパークラスと呼ばれる別のクラスのプロパティとメソッドを継承できます。コアクラスおよび Flash Player ActionScript クラスの多くと同じように、独自のカスタムクラスを拡張することができます。TextField クラスは拡張できません。

2 つのクラス間にこのような関係を作るには、class ステートメントの extends 節を使用します。スーパークラスを指定するには、次のシンタックスを使用します。

class SubClass extends SuperClass {}
SubClass に指定したクラスは、SuperClass によって定義されているプロパティとメソッドをすべて継承します。

ってことは、スーパークラスってのは、aクラスのスーパークラスはAクラス、bクラスのスーパークラスはBクラスっていう風に、サブから見てスーパーなだけで、親子関係に似ている感じかな。
で、この記事はカスタムクラスを作成する記事なんだけど、自分でサブクラスを作れちゃうんだな。その自分で作ったサブクラスをカスタムクラスという。
このカスタムクラスを作るときに、アクションスクリプトで既に定義されているクラスをスーパークラスとして指定できるよって話。


でもって、アクションスクリプトのクラスもObjectクラスからサブクラスへ継承されて、さらにサブクラスへ継承されているといった構造になっている模様。

ActionScript3.0 コンポーネントリファレンス

リファレンスで適当にクラスを覗いてみると、「継承」という項目がある。
例えばArrayクラスを見ると「継承 Array→Object」って書いてある。
他のクラスも覗いてみると、継承の最後はObjectになってる。
つまり、Objectクラスが大元ってこと。

Objectクラス

そこで、オブジェクトクラスを覗いてみると、うわっ!って思うほどのサブクラスの羅列。
でもここに書かれているのは、Objectクラスのサブクラスで、全てのクラスじゃないだな。
つまりArray→Objectって書いてるやつだけで、XMLSocket→EventDispatcher→Objectとかなってるやつは含まれてない。
なぜならXMLSocketはEvetDispatcherのサブクラスだから。


次に、継承って何が継承されてるの?って話。
リファレンスでArrayクラスを覗いてみる。
ActionScript3.0 リファレンス Arrayクラス

このクラスに含まれるプロパティ・クラス・定数が書いてあり、
右端に「定義元」って書いてる。
Arrayの場合はObjectかArrayのいずれかが書いてあり、Objectと書かれた欄の左端には上向き矢印が付いてる。
これはObjectクラスから継承されたもの。
Arrayと書かれたものが、「拡張」または「オーバーライド」されたもの。
拡張というのは、追加することで、オーバーライドは変更すること。
つまり、サブクラスには、スーパークラスからそのまま継承したものと、新たに追加したものと、内容を変更したものがある。

posted by K at 01:02| Comment(0) | OOP | このブログの読者になる | 更新情報をチェックする