ObjectSquare [1999 年 4 月号]

[Happy Squeaking!!]


5.Squeak演習: インターセッション

5.3 メタクラス・クラスを支えるもの つづき


クラス自身の属性 - クラスインスタンス変数

インスタンスが属性の値を保持できるように、クラス自身も値を保持できます。クラスが持つべき属性の定義は、操作と同様やはりメタクラスで行なうことができます。
インスタンス生成の操作をクラスが担当する一方で、クラスの属性は、生成するインスタンスを管理するためによく使われます。例えば、作られたインスタンスをすべてプールしておく集合オブジェクトを持ったり、インスタンス生成の際、インスタンス固有のid番号をカウントするなどがその例です。

では、Accountメタクラスにdefinitionメッセージを送ってみましょう。以下のような文字列が帰ってきます。

Account class definition
        => 'Account class instanceVariableNames: '''''

これは普段見慣れているクラス定義用のテンプレート文字列とは少し異なっています。クラスにくらべ、メタクラスのほうが定義できる変数の種類の数が少なくなっているのです。しかし、クラス自身がもつ変数は、このテンプレートを埋めることで定義ができるので、とりあえずはこれで十分です。

ここでは、銀行口座が新規に作られたときに、id番号をカウントして新規インスタンスに与えられるように、idCountという変数を定義することにします。

ブラウザを開き、Account classのdefinitionを表示させます。
''の中に idCountと書いて"accept"してください。


クラスインスタンス変数 idCountの定義

これで、Accountクラスが持つことのできる属性、'idCount'が定義できました。

この「一つ一つのクラスがもつ変数」のことをSmalltalkでは、「クラスインスタンス変数」と呼んでいます。いささかややこしい名前ですが、クラスをあたかもインスタンスのように、値を保持するものとして扱っているからと考えるといいでしょう。

Smalltalkにはまた別に「クラス変数」というものもあります。これは一種の共有変数で、「クラス」と「インスタンス(群)」が、一緒に参照、書き込みができるという性質を持っています。JavaやC++のstatic(静的)変数に、比較的近いと言えます。今回は扱いません。

クラスインスタンス変数は、クラスが自由に扱うことのできる変数です。クラスメソッドの中でのみ利用でき、インスタンスからは触ることができないようになています。

idCountを先ほど定義したクラスメソッドnewの中で使うことにします。
以下のような実装になります。

new
        idCount := idCount + 1. "クラスインスタンス変数 idCountを増加"
        ^super new initiallize;
        id: idCount
        "増加したidCountを生成したインスタンスに渡す"

ただし、idCountはまだ初期化されていないので、これだけではエラーになります。これを防ぐため、インスタンスメソッドにinitializeを定義したのと同様、クラスメソッドにもinitializeを定義することになります。
(かたや「インスタンス」の初期化、かたや「クラス」の初期化です。いうまでもないですが、両者は全く別々のオブジェクトです。混乱しないようにしてください)。

メッセージカテゴリ"class initialization"を、ブラウザの"class"側で追加します。


"class initialiation"メッセージカテゴリをクラス側で追加

initializeメソッドの実装は以下のようになります。

initialize
        idCount := 0

"accept"してください。これで定義されました。


クラスメソッドinitializeの定義

ワークスペースで、Account initializeとdo itしてください。これによりidCountが初期化され、クラスがこの変数を使える準備が整ったことになります。

最後に、新しく定義されたnewメソッドでは、生成したAccountインスタンスに対し、idCountによって振られたidを設定するためのid: メッセージを送っています。
これはインスタンスの行なうことなので、メタクラスにではなく、クラスに操作として定義します。ブラウザを"instance"サイドに切り替えて、以下を"accept"してください。

Account のid:メソッド (accessingメッセージカテゴリ)
id: newId
        id := newId.

以下はここまでの修正を加えたAccountクラスです。
FileIn: BankApplication2.st (<=Click)

ファイルインにより、Account initializeは自動的に実行されるようになっています。そのためこのソースをそのまま用いる場合は、単にファイルインするだけで動作確認ができます。
SmallTip: ファイルインにより、ファイルインしたクラスのクラスメソッド initializeが自動的に起動される

では以下を何回か実行してみましょう。

| acc |
acc := Account new.
acc deposit: 1000.
acc inspect.

一回目、二回目と、インスタンス生成ごとにid番号が振られているのが確認できます。


クラスのnew内の作用によって自動的にidが降られたAccountインスタンス

インスタンスはオンデマンドで作られるオブジェクトであるのに対し、クラスはテンプレート文字列を埋めて定義した瞬間から、Squeak環境の中に居座ることになります。従って両者のオブジェクトの保持する変数のライフサイクルは全く異なり、この例の場合では、AccountクラスのidCountは明示的にワークスペースなどでAccount initializeと実行しない限り、増加した値が保たれることになります。Accountクラスが存在する限り残る、半永続的なものになります。

© 1999-2001 OGIS-RI Co., Ltd.

Prev.

Index

Next