なるほど、博士がプログラムなんか書けと言ったのは、「クラス変数」の使い方を実感させるためだったのか。やるなヒゲオヤジ。
クラスの中に定義して、そのクラスのオブジェクトが共通に使う変数、それが「@」が二個ついた変数「クラス変数」だったのだ。
総費用を示す変数を、クラス変数「@@total」にしよう。クラスEnemyの定義の中で、@@totalに初期値0を与えておくと、Rubyインタプリタでこの定義が読み込まれたときに、@@totalの値は0になる。
各オブジェクトの費用はインスタンス変数@costで示されるから、リスト2-1のようなメソッドtotal_costをクラスEnemyに定義してやればいい。
リスト2-1 メソッドtotal_cost
def total_cost @@total+=@cost puts "総費用:#{@@total}" end
トップレベルでは、たとえばリスト2-2のようにオブジェクトe1を作成したら、e1がtotal_costを呼び出す。これで、「e1の費用」が「総費用」に足しこまれる。
リスト2-2 トップレベルでメソッドtotal_costを使用する例
e1=Enemy.new("E-1", 5000)
e1.total_cost
実際は、@costの値を与えるメソッドcostと一緒にリスト2-3のように書いてもヨイ。
リスト2-3 メソッドcostを用いたメソッドtotal_cost
def cost @cost end def total_cost @@total+=cost puts "総費用:#{@@total}" end
さらに各オブジェクトの費用を報告するメソッドの中でメソッドtotal_costを呼ぶようにしちゃえば、オブジェクトはreportさえ呼び出せば自身の費用と総費用を報告できるようになる。
リスト2-4 メソッドreportの中でtotal_costも呼んじゃう
def report puts "#{name}作成費用:#{cost}" total_cost end
というわけでクラス変数@@totalを使った新生プログラムreport2.rbがリスト2-5のようになる。実行結果は同じ。
リスト2-5 report2.rb
#-*- coding: shift_jis -*- ###クラスEnemyの定義### class Enemy @@total=0 #クラス変数 def initialize(name, cost) @name=name @cost=cost end def name @name end def cost @cost end def total_cost #そのオブジェクトの費用を足し込む @@total+=cost puts "総費用:#{@@total}" end def report puts "#{name}作成費用:#{cost}" total_cost end end ###トップレベル### e1=Enemy.new("E-1", 5000) e1.report #total_costも一緒に呼ばれる e2=Enemy.new("E-2", 3000) e2.report e3=Enemy.new("E-DX", 8500) e3.report #あれ。結局繰り返しかヨ
コードは短くはなったが、やっぱりe1, e2, e3が違うってだけでおんなじこと繰り返してーんじゃーん。これナントカならないのッ!?
待てよ。繰り返しになっちゃうのは、「オブジェクトがそれぞれメソッドを呼び出さなきゃいけない」からだ。「全てのオブジェクトが共通に使う値」がクラス変数なら、「全てのオブジェクトが共通にする処理」は...フフフフフ、あったじゃないか。