クラスと変数とメソッドの話
 オブジェクト指向の短いサンプルというとどうしてもアルゴリズミックな話題になってしまいますが、 ここで使うクラス「Moroqueue」とはこのよーなものです。 というのを最初に概略だけ紹介してみます。
  • 任意の数値や文字列が並んだデータ構造を管理します。
  • この並びにデータを追加する場合、一番後ろにしか追加できません。
  • この並びからデータを取り出す場合、一番前からしか取り出せません。
あら?これはその、世間様では「キュー」(queue) と呼ばれるデータ構造ではないですか? いやいや、このMoroqueueはただのキューではないんですな…
  • 新しい要素を追加する際、 それと同じ値が既に入っていたら、それを消して前に詰め、一番後ろに追加する。
すごいでしょう(どこがやねん)「そんな特徴、何に使うんだ」ですって? 皆さんは仮想記憶とかキャッシュという言葉を聞いたことがありますか? ではLRU(Least Recently Used=最小使用頻度)アルゴリズムとゆーのも。 そのとおおり、これはLRUアルゴリズムで使うキューの最も簡単なサンプルというわけです。
package require Itcl

class Moroqueue {
    variable Q
    constructor {args} {
        set Q $args
    }
    method enqueue e {
        if {[set p [lsearch -exact $Q $e]] != -1} {
            set Q [lreplace $Q $p $p]
        }
        lappend Q $e
    }
    method dequeue {} {
        set r [lindex $Q 0]
        set Q [lreplace $Q 0 0]
        return $r
    }
    method get {} { return $Q }
}

Moroqueue mo 5 6 7
puts [mo get]
mo enqueue 4; puts [mo get]
mo enqueue 8; puts [mo get]
mo dequeue;   puts [mo get]
mo enqueue 7; puts [mo get]
mo dequeue;   puts [mo get]
mo enqueue 8; puts [mo get]
mo dequeue;   puts [mo get]
# end.

 [incr Tcl]のOO文法でもやはり基本はクラスの定義で、 これはclassコマンドで大きくブロックを囲むことで行えます。 で、このブロックにつける名前、 つまりclassコマンドの最初の引数がクラス名と呼ばれるものです。  この例では、Moroqueueという名前のクラスをひとつ定義しています。

 クラスのブロック内で共通して使える変数、C++ではメンバ変数、 Javaではインスタンス変数と呼ばれますが、は、 variableコマンドで宣言・定義することができます。 (以後インスタンス変数と呼ぶことにします)

  variable profiles
  variable filename "untitled"
2番目のように、宣言と同時に値を代入することもできます。

 クラスが「インスタンス化」(↓)されるときに実行される特別なプロシージャを コンストラクタと言います。 コンストラクタはprocの代わりにconstructor コマンドを使うほかはTcl言語のプロシージャと全く同じです。 コンストラクタには、普通インスタンス変数の初期化処理を書いておきます。

 さてクラス内では、クラスに属するプロシージャ、という意味で、 標準Tclのprocは使わずに、 代わりにmethodというコマンドを使います。 methodコマンドで定義した、 クラスに属するプロシージャのことをメソッドと言います。 メソッドの書き方自体は、Tcl言語の構文と同じです。 プロシージャの中でローカルな変数を使うことができるほか、 インスタンス変数も、特に断りなく勝手に使うことが出来ます。

    method enqueue e {
      if {[set p [lsearch -exact $Q $e]] != -1} {
        set Q [lreplace $Q $p $p]
      }
      lappend Q $e
    }

 クラスというのは単にいくつかの変数といくつかのメソッドでデータ構造というか枠組みを定義しただけのものなので、 実際にそれを使うにはインスタンス化 (「オブジェクト」をつくること) という処理を行わせる必要があります。 インスタンス化は、[incr Tcl]ではこのようにして行います。

Moroqueue mo 5 6 7
つまり、「Moroqueue」というクラスを定義することは、 [incr Tcl]では「Moroqueue」 というTclコマンドを作ることでもある、という点が一点、 そのMoroqueueというコマンドは Moroqueueクラスのインスタンス化を行うコマンドだという点が一点、
  Moroqueue インスタンス名 引数...
インスタンス名は、[incr Tcl]のマニュアルなどでは オブジェクトハンドル と呼ばれていることもあります。これはインスタンスを一意の識別できる名前なら何でもOKです。 その後ろの引数の並びは、 そのままMoroqueueクラスのconstructorで定義されたコンストラクタがあれば、 それに渡され、コンストラクタの定義通り処理が行われます。

  mo enqueue 4
これが[incr Tcl]でのメソッドの呼び出しの最も簡単な例です。 つまりインスタンス名にメソッド名をつけ、 あればその後ろに引数を空白で区切って並べていくという、 Tkウィジェットのウィジェットコマンドと全く同じやり方が通用します。

拡張レビュー分室 top
(first uploaded 1999/10/19 last updated 2000/11/18, EK)