コモンなものたち登場
 今度は、 キューに保持できる要素の最大数を昼間は50、夜は10と変えるようにしています。 妙なサンプルだこりゃ。 ていうか夜のほうがトランザクションが少ないと誰が決めたのです?
package require Itcl
class Moroqueue {
    private variable Q
    private common   QUEUE_LENGTH

    set h [clock format [clock seconds] -format %H]
    if {$h >= 9 && $h <= 18} {
        set QUEUE_LENGTH 50
    } else {
        set QUEUE_LENGTH 10
    }

    constructor {args} { set Q $args }

    private method isfilled {} {
        if {[llength $Q] >= $QUEUE_LENGTH} { return 1 } { return 0 }
    }

    private proc isValidValue e {
        return [expr { ("[string trim $e]" == "") ? 0 : 1 }]
    }

    public method enqueue e {
        if {! [isValidValue $e]} {
            error "Ootto! Input value '$e' is invalid."
        }
        if {[isfilled]} {
            error "Ootto! Queue size exceeds maximum."
        }
        if {[set p [lsearch -exact $Q $e]] != -1} {
            set Q [lreplace $Q $p $p]
        }
        lappend Q $e
    }

    public method dequeue {} {
        set r [lindex $Q 0]; set Q [lreplace $Q 0 0]
        return $r
    }

    public method get {} { return $Q }
}

set m1 [Moroqueue mo#auto 5 6 7]
set m2 [Moroqueue mo#auto]
puts [$m1 get]
#$m1 enqueue {}
$m1 enqueue 4; puts [$m1 get]
$m1 enqueue 8; puts [$m1 get]
set a [$m1 dequeue]; $m2 enqueue $a
puts "[$m1 get] / [$m2 get]"
$m1 enqueue 7;
puts "[$m1 get] / [$m2 get]"
set a [$m1 dequeue]; $m2 enqueue $a
puts "[$m1 get] / [$m2 get]"
$m1 enqueue 8;
puts "[$m1 get] / [$m2 get]"
set a [$m1 dequeue]; $m2 enqueue $a
puts "[$m1 get] / [$m2 get]"
# end.

 今度のコードの中には、 下のように、どのメソッドにも属さない位置に実行文が書かれている箇所があります。 この部分は、このスクリプトが処理系に読みこまれるときに一度だけ実行されます。
    set h [clock format [clock seconds] -format %H]
    if {$h >= 9 && $h <= 18} {
        set QUEUE_LENGTH 50
    } else {
        set QUEUE_LENGTH 10
    }

 変数をpublicにすることは、OOの常識ではあまりよくないこととされています。 C++なら、クラスの代わりに構造体を使えば済むので確かにそうなんですが、 Javaのようにクラスの他にクラスなし(は?)という言語だと例えば

  class Rectangle {
    public int x, y, width, height;
  };
  Rectangle rectan = new Rectangle();
  rectan.x = 10; rectan.y = 20;
こんなクラスはむしろ変数をpublicにしておいた方が扱いやすいでしょう。 というわけで、[incr Tcl]でも、publicの変数はクラスの外から直接参照したり書き換えたりできるのですが、 そのやり方がちょっと変わっていて、なんつーかTcl的というかTk的というか、 なのであります。
   set tora [$pm cget -Translation]
   $pm configure -Translation crlf
つまり、public変数の外からの読み書きにはcgetと configureを使います。変数はどこかというと、 オプションが変数名になっています。つまり、public変数の名前が「Translation」 の場合、cget&configureで指定するオプションが「-Translation」 と、こうなっています。

 さて話は変わりまして、いわく通常、 クラスのインスタンスはそれぞれ別々のデータを持ち、 あるインスタンスのデータをいじっても、 同じクラスでも違うインスタンスのデータは影響を受けません。 10個インスタンスを作ったら10個のデータセットが独立に存在します。 互いに影響を受けていつのまにか混ざったりということはありません。 しかし、定数のような個々に持たせる必要のない場合は、 変数やメソッドを「クラスにつきひとつ」定義させることもできます。

 [incr Tcl]ではクラスにつきひとつ定義される変数を共通変数(common variable)と呼び、 variableコマンドの代わりにcommonコマンドで定義します。 これは、C++やJavaでstaticがついた変数に相当します。 共通変数にも、publicやprotected、privateをつけることができます。 普通共通変数は、下のように定数を定義するのに使うことになるでしょう。

    private common LENGTH_MAX 50
 これに対し、クラスにつきひとつ定義されるメソッドはコモンプロシージャ(common procedure)と呼びます。 これは、Javaでいうクラスメソッドのことです。コモンプロシージャは、 methodコマンドの代わりにprocコマンドで定義します。 こちらも、C++やJavaでstaticをつけたメソッドに相当します。
    private proc isValidValue e {
        return [expr { ("[string trim $e]" == "") ? 0 : 1 }]
    }
コモンプロシージャの中では、インスタンス変数は参照できず、 メソッドにアクセスすることもできません。そのため、 与えられた引数を元に全ての処理を行い、結果を返す形になります。 これも、C++やJavaのクラスメソッドと共通した特徴です。

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