Section 2.5 メンバプロパティ

今回はメンバプロパティについてなんだけど、前にメンバプロパティ使ったの覚えてる?
まぁ、あの時は単にプロパティって呼んでたけどね。
えっと、それって文字列の length プロパティとか、配列の count プロパティのこと?
そうそう。それぞれ §1.11§1.14 で使ったよね。
じゃあプロパティの使い方は覚えてる?
文字列.length』とか『配列.count』っていう感じだよね。
ん、そう。
こんなふうに、プロパティはクラスのメンバ変数みたいに使えるんだ。
あ、そういえばクラスのメンバ変数をクラスの外から使うときも『クラス名.メンバ変数名』って書くんだよね。
そ。でも、プロパティはメンバ変数みたいに使えるけど、実際にはメソッドに近いんだ。
そうなの? …っていうか、プロパティってどういうものなの?
メンバ変数の値って、クラスの外からでも自由に参照したり変更したりできるよね。
うん、そだね。
でも、クラスの外から勝手にメンバ変数の値を操作されると困る場合もあるんだ。
で、プロパティはメンバ変数に不正な値がセットされるのを防いだり、メンバ変数を読み出し専用にしたりするのに使えるの。
ちなみに文字列の length プロパティは読み出し専用なんだよ。
へぇ、そうなんだ。
というワケで、今回はプロパティの作り方と使い方を見ていくね。
あ、あとクラスに属してるプロパティは正確にはメンバプロパティって呼ぶんだけど、 明らかにメンバプロパティって判る場合には単にプロパティって呼ぶことにするね。
うん、わかった。
じゃあ、まずはプロパティの作り方から。
§2.3Calculator クラスを作った時に、ans っていうメンバ変数があったよね。
うん。計算結果を入れとくメンバ変数だったよね。
そう。
これをプロパティを使って操作できるようにするとこうなるよ。

<プロパティを通じて計算結果を取得できるようにした Calculator クラス>

class Calculator
{
    var ans;  // 計算結果を格納するメンバ変数

    function Calculator()  // コンストラクタ
    {
        ans = 0;  // メンバ変数を初期化します
    }

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

    // 計算式の入力を求めるメソッド
    // OK ボタンが押されると式の計算をした後 true、キャンセルボタンが押されると false を返します
    function calculate()
    {
        var expr = System.inputString("電卓""数式を入力してください。""");
        if(expr === void)
            return false;

        answer = expr!;  // 入力された式の値を計算して、プロパティを通じて計算結果を ans に代入します

        return true;
    }

    // メンバ変数 ans を操作するためのメンバプロパティ
    property answer
    {
        // セッター:引数が整数型か実数型なら ans に代入します
        setter(value)
        {
            if((typeof value == "Integer") || (typeof value == "Real"))
                ans = value;
            else
                System.inform("メンバ変数 ans に不正な値を代入しようとしました。""エラー");
        }

        // ゲッター:ans の値を返します
        getter()
        {
            return ans;
        }
    }
}
// Calculator クラスの定義はここまで

// Calculator クラスのオブジェクトを作成します
var calc = new Calculator();

// 計算式の入力を求めて、入力されれば計算結果を表示します
if(calc.calculate())
    System.inform(calc.answer, "計算結果");

invalidate calc;  // 不要になったので無効化します

answer っていうのが、メンバ変数 ans を操作するためのプロパティ。
プロパティって、メンバ変数とは違う名前になるの?
うん。プロパティは変数と同じように扱えるから、メンバ変数と同じ名前だったらプロパティとメンバ変数の区別がつかなくなっちゃうでしょ。
あ、そっか。だから違う名前にしなくちゃいけないんだ。
そういうこと。
で、プロパティの書き方はこうね。

<プロパティの書き方>

property プロパティ名
{
    setter(引数)
    {
        // セッターの内容
    }

    getter()  // getter の後ろのカッコは省略できます
    {
        // ゲッターの内容
        return ゲッターの返す値;
    }
}

プロパティは値を設定するためのセッター(setter)と、値を取得するためのゲッター(getter)の2つで出来てるんだ。
どっちも関数みたいだね。
うん、セッターもゲッターもメソッドに近いね。
ちなみにセッターには引数が1つだけあって戻り値がないんだ。
で、ゲッターには引数がなくて戻り値があるんだよ。
それって決まってるの?
うん、決まってるよ。
セッターは値を設定するわけだから、その設定する値が引数になるんだ。戻り値は必要ないよね。
で、ゲッターは値を取得するんだから、戻り値が必要で、引数は要らないよね。
なるほど、確かにそうなるね。
あと、セッターとゲッターはどっちか片方だけでも OK。
ゲッターだけのプロパティは読み出し専用で、 セッターだけのプロパティは(あんまり使わないと思うけど)書き込み専用なんだ。
ってことは、値を変えられたくないメンバ変数の操作にはゲッターだけのプロパティを使えばいい、ってこと?
そうそう、そういうこと。
じゃあ answer プロパティを見ていくね。
うん。
まずはセッターから。

answer プロパティのセッター>

// セッター:引数が整数型か実数型なら ans に代入します
setter(value)
{
    if((typeof value == "Integer") || (typeof value == "Real"))
        ans = value;
    else
        System.inform("メンバ変数 ans に不正な値を代入しようとしました。""エラー");
}

answer プロパティのセッターは、引数、つまり設定される値が整数型か実数型ならその値をメンバ変数 ans に代入するんだ。
もしそれ以外の型の値を設定しようとした場合はエラーメッセージを表示するよ。
引数の型をチェックしてるのが if の条件式のところだよね?
ん、そう。
typeof 演算子は §1.6 で説明したよね。
うん。
value が整数型だったら "Integer" で、実数型だったら "Real" になるんだよね。
そうそう。
じゃあ、引数が整数型か実数型なら条件式が真になって、引数の値が ans に代入されるけど、 それ以外の型だったら、条件式が偽になってエラーメッセージが表示されるってことかな?
そ。こんなふうにして不正な値が設定されるのを防げるってワケ。
なるほどね。
ただ…
ん? なに?
例えば、読み出し専用の answer プロパティを作っても ans が読み出し専用の変数になるわけじゃないんだ。
だから、『calc.ans = 0;』みたいに直接 ans に値を代入するとプロパティの意味がなくなっちゃうから注意してね。
じゃあ、セッターがあっても ans に直接値を代入しちゃったら、データ型のチェックができなくなっちゃうの?
うん、だからこういう場合はちゃんとプロパティを使ってメンバ変数を操作するようにしてね。
はーい。
じゃ次はゲッターの方ね。

answer プロパティのゲッター>

// ゲッター:ans の値を返します
getter()
{
    return ans;
}

これは ans の値をそのまま返してるだけだね。
うん、ゲッターの方は特にチェックとか要らないからね。
そっか。
§2.3 では ans の値は getAnswer メソッドを使って 『a = calc.getAnswer();』っていうふうに取得してたけど、プロパティを使うと『a = calc.answer;』で取得できるようになるんだ。
あ、そういえば今回のスクリプトには getAnswer メソッドがないね。
うん。
getAnswer メソッドみたいに、単純にメンバ変数の値を返すだけのメソッドなら、こうやってプロパティにした方がすっきりした書き方ができるでしょ。
確かにそうだね。
それじゃ、今回のスクリプト実行してみて。
今回は calculate メソッドの中で計算式の値を ans に代入するときにもプロパティを使ってるよ。
あ、ほんとだ。
じゃあ実行してみるね。
まずは普通の数式を入力してみて。
わかった。
じゃあ、『2*3』って入力して、OK。

<実行結果>

表示されたメッセージ(計算結果)

ちゃんと「6」って表示されたね。
calculate メソッドで『answer = expr!;』が実行される時に、 『setter(2*3)』っていう形でセッターが呼ばれるんだ。
これだとセッターの引数が整数型になってるから OK なんだよね?
ん、そう。
つまり条件式が真になって、計算結果の 6ans に代入されるってわけだね。
その後 inform メソッドで計算結果を表示する時には、ゲッターの方が呼ばれるんだよね?
ん。ゲッターは ans の値をそのまま返してるだけだから…
6」って表示されるんだね。
ん、そういうこと。
じゃあ、今度はセッターに渡す値が正しくない場合を見てみるから、もう一回実行して。
うん、わかった。
……今度はどんな式を入力すればいいの?
"a"+"b"』って入力してみて。
えっ、式に数字と演算子以外を入れるとエラーになるんじゃなかったっけ?
あ、ゴメン。説明するの忘れてた。
文字列が入ってる足し算は OK。結果は文字列を連結したものになるよ。
そっか。文字列も足し算できるもんね。
じゃあ、『"a"+"b"』で OK、と。

<実行結果>

表示されたエラーメッセージ

あっ、今度はエラーメッセージが表示されたね。
文字列同士の足し算の結果は文字列型になるからね。
じゃあ、条件式が偽になってエラーメッセージが表示されたんだね。
うん、そういうこと。
これでプロパティについてはだいたい解った?
うん、だいじょぶだと思う。
じゃ、今回はこれくらいにしとこっか。
それじゃまた次回ね。


前へ | TOP | 次へ