Section 2.12 ポリモーフィズム

第2章、クラス編の最後はポリモーフィズムについて。
なんかクラス関係って聞いたことない用語が多いね…
ま、確かに聞き慣れない用語が多いよね。
ちなみにポリモーフィズムは「多態性」とか「多相性」とか言ったりもするよ。
それはそれで聞いたことない用語なんだけど…
具体的にはどういうものなの、ポリモーフィズムって?
例えば、A っていうクラスと B っていうクラスがあって、 それぞれこんなふうに定義されてるとするね。

<クラス A, B

class A
{
    function A(){}  // コンストラクタ(何もしません)

    function finalize(){}  // デストラクタ(何もしません)

    // メッセージを表示するメソッド
    function message()
    {
        System.inform("A");
    }
}

class B
{
    function B(){}  // コンストラクタ(何もしません)

    function finalize(){}  // デストラクタ(何もしません)

    // メッセージを表示するメソッド
    function message()
    {
        System.inform("B");
    }
}

A とか B を表示する message メソッドがあるだけ…ずいぶんシンプルなクラスだね。
うん。
で、あと A, B クラスとは別に showMessage っていう関数があって、こう定義されてるとするね。

showMessage 関数>

function showMessage(object)
{
    object.message();  // object の message メソッドを呼び出します
}

これもシンプルだね。
えっと、これってクラス AB のオブジェクトが引数になるの?
うん、そだよ。
で、クラス A, BshowMessage 関数を定義した後に、このスクリプトを実行するとどうなると思う?

var a = new A();
var b = new B();
showMessage(a);
showMessage(b);
invalidate a;
invalidate b;

えっとね… a を引数にして showMessage 関数を呼び出すと、 objecta に置き換わって a.message(); になるから…
A」って表示されるよね。
うんうん。
次の showMessageb が引数になってて、 objectb に置き換わるから「B」って表示されるね。
そ。これがポリモーフィズム。
えっ、どういうこと?
showMessage 関数の中で呼び出してる message メソッドって、 引数にどっちのクラスのオブジェクトを指定するかで結果が変わるよね。
うん。objectA クラスのオブジェクトだったら「A」って表示されるけど、 B クラスのオブジェクトだったら「B」って表示されるよね。
つまり、引数に指定するオブジェクトに応じて色んな動作をする性質がポリモーフィズムってこと。
ちなみにポリモーフィズムってのは「色んな姿を見せる」って意味ね。
なるほど、そういうことね。
でも、これって何の役に立つの?
んー、例えばこういう場合にポリモーフィズムが使えるよ。

// ここに FileSelector クラスの定義を書きます

// 指定されたファイルをメモ帳で開くクラス
class NotePad
{
    var selector;  // FileSelector クラスのオブジェクト

    function NotePad()
    {
        selector = new FileSelector();
    }

    function finalize()
    {
        invalidate selector;
    }

    // ファイル選択ダイアログボックスを表示します
    // ファイルが選択されれば真、キャンセルされれば偽を返します
    function input()
    {
        return selector.openFile();
    }

    // 選択されたファイルをメモ帳で開きます
    function showResult()
    {
        System.shellExecute("notepad", Storages.getLocalName(selector.name));
    }
}

// 電卓クラス(簡易版)
class Calculator
{
    var ans;  // 計算結果を保存しておくメンバ変数

    function Calculator()
    {
        ans = 0;
    }

    function finalize(){}

    // 数式の入力を求めます
    // OK ボタンが押されると数式の値を計算・保存して真を返します
    // キャンセルボタンが押されると何もせず偽を返します
    function input()
    {
        var expr = System.inputString("電卓""数式を入力してください。""");
        if(expr === void)
            return false;

        ans = expr!;

        return true;
    }

    // 計算結果を表示します
    function showResult()
    {
        System.inform(ans, "計算結果");
    }
}

// 時間を計算するクラス
class Time
{
    var minute;

    function Time()
    {
        minute = 0;
    }

    function finalize(){}

    // 時間(分)の入力を求めます
    // OK ボタンが押されると入力された値を保存して真を返します
    // キャンセルボタンが押されると何もせず偽を返します
    function input()
    {
        var value = System.inputString("何分後?""数値を入力してください。""");
        if(value === void)
            return false;

        minute = +value;

        return true;
    }

    // 今から minute 分後の時刻を表示します
    function showResult()
    {
        var d = new Date();
        var min = d.getMinutes() + minute;
        var hour = (d.getHours() + min \ 60) % 24;
        min %= 60;

        System.inform("今から " + minute + " 分後は " + hour + " 時 " + min + " 分です。");
    }
}


// ポリモーフィズムのための関数
// 引数は NotePad クラス、Calculator クラス、Time クラスのオブジェクトのどれかになります
function polymorphism(object)
{
    if(object.input())        // 入力を求めます
        object.showResult();  // 入力された場合は処理結果を表示します
}


// それぞれのクラスのオブジェクトを作ります
var objects = new Array();
objects[0] = new NotePad();
objects[1] = new Calculator();
objects[2] = new Time();

while(true)
{
    var input = System.inputString("番号を入力してください。""1: NotePad, 2: Calculator, 3: Time""");
    if(input === void)
        break;  // キャンセルボタンが押されると終了します

    input = +input - 1;  // 配列の添え字に対応させるために 1 マイナスします
    if(input == 0 || input == 1 || input == 2)
        polymorphism(objects[input]);  // 対応するオブジェクトを引数にして polymorphism 関数を呼び出します
    else
        System.inform("1 から 3 の数字を入力してください。""エラー");
}

invalidate objects[2];
invalidate objects[1];
invalidate objects[0];

うわ、長いね〜。
まぁね。
でも NotePad クラスも Calculator クラスも Time クラスも前に似たようなの作ったでしょ。
確かに、全部見たことある感じのスクリプトだね。
というワケで、NotePad クラスと Calculator クラスと Time クラスの説明は省略するね。
うん、OK だよ。
じゃ、まず説明の前に実行しとこっか。
今回はスクリプトが長いからファイルにまとめといたよ。
りょーかい!

入力ウィンドウ

えっと、これって数字を入力すればいいの?
ん。1, 2, 3 のどれかを入力して OK ボタンを押してみて。
じゃあ、最初は 1 で、OK。
1NotePad になってるから、メモ帳を起動してファイルの中身を表示するんだよね?
うん。
「ファイルを開く」ダイアログボックスが表示されるから、ファイルを選択して「開く」を押せばいいんだよね。

NotePad の実行結果>

メモ帳

ちゃんとメモ帳が起動したね。
じゃ次いってみよっか。
じゃあ次は、2 を入力して、OK。
2Calculator だから電卓だね。
ん、そう。

数式の入力ウィンドウ

これって、前と同じように式を入力すればいいの?
うん、何か数式を入力してみて。
じゃあ『(65-43)/2』って入力して、OK。

Calculator の実行結果>

計算結果

えっと、(65-43)/222÷2 だから、11 で合ってるよね。
じゃあ、最後に 3Time だね。
うん。3 を入力して OK、と。

時間の入力ウィンドウ

これも前と同じなんだよね?
うん。
じゃあ、100 って入力して、OK。

Time の実行結果>

表示されたメッセージ

えっと、今 2015 分だから、100 分後は… 2155 分。
うん、合ってるね。
ポリモーフィズムを使うと、こんな感じに3つの機能を全部組み込んだスクリプトがスッキリ書けるんだ。
じゃ、まずは polymorphism 関数から見てこっか。
は〜い!
NotePad クラスCalculator クラスTime クラスにはそれぞれ input メソッドと showResult メソッドがあるよね。
input メソッドが入力を処理するメソッドで、showResult がその結果を表示するメソッドだよね?
そーそー。
で、input メソッドはデータが入力されると true、 キャンセルされると false を返すように統一されてるから…
データが入力されたら showResult メソッドが実行される、ってことだね。
ん、そういうこと。
ポリモーフィズムの対象になるクラスのメソッドは、名前と引数、あと戻り値の型と意味を合わせとくんだ。
そっか。引数も同じになるし、戻り値の扱いも同じだから、合わせとく必要があるんだね。
うん。
じゃあ、次はオブジェクトを作る部分のスクリプトね。
最初にそれぞれのクラスのオブジェクトを作って配列に入れてるね。
入力された番号によってどのオブジェクトを引数にするかが決まるから、 配列にしとけば、入力された番号を添え字として使えて便利だからね。
あ、なるほどね。
で、後は inputString メソッドで入力を受け取って…
入力された値が 1, 2, 3 のどれかだったら、 配列の添え字にするために 1 引いてから、 配列に入ってるオブジェクトを polymorphism 関数に渡すんだね。
ん、そう。
こうすることで、オブジェクトごとにいちいち関数を作らなくてもよくなるってワケ。
う〜ん、ポリモーフィズムも便利そうだけど、やっぱり上手く使いこなすのが難しそうだよね。
どういうときにポリモーフィズムを使ったらいいのかとかもよく解らないし…
確かにポリモーフィズムとか、あと前に説明したクロージャや incontextof 演算子とかも、使い方よりどこで使えばいいかってのを判断する方が難しいかもね。
今回のスクリプトもポリモーフィズムを使わずに書くこともできるわけだしね。
だよねぇ…
まぁ、とりあえずはちゃんと思った通りに動くスクリプトが書けるようになることを目標にしたらいいんじゃないかな。
それが出来るようになってから、わかりやすくてすっきりしたスクリプトとか効率的なスクリプトを書くことに挑戦したらいいわけだし。
うん、そだね。
じゃあ、第2章はこれで終わり。
次回から第3章に入るね。
第3章は何をやるの?
ウィンドウとかレイヤ関係かな。
あとサウンド再生とかについてもやるつもりだよ。
なんか KAG っぽくなってきたね。
うん。でもタグは使わずに全部 TJS で書いてくから。
あと、第3章で §0.3 の目標を達成するからね。
ってことは、あの時計を完成させるってこと?
うん、そういうこと。
第3章も長くなると思うけど、KAG に色んな機能を追加したりするのに必要なことがたくさんあるから。
そうなんだ、それはちょっと楽しみかも。
というワケで、次の章もしっかりついてきてね!
うん、わかった。がんばるね!


前へ | TOP | 次へ