「フツーはオブジェクトを生成して、必要な設定をする」程度に思われているinitializeメソッド」でreportメソッドを呼ぶことはやめて、create_and_reportというメソッドを新しく作る。
まず、クラスメソッドの定義には「self.(ドットがついてる)」とつける。
リスト5-1 create_and_reportメソッドの定義
def self.create_and_report(name, cost)
このcreate_and_reportメソッドの中で、newメソッドを呼ぶことができる。newもクラスメソッドだから、そのクラス自身の定義の中で呼ぶときはself.をつける。
生成したオブジェクトは、変数名eを与えておく。
リスト5-2 newメソッドを呼ぶ
e=self.new(name, cost)
生成したオブジェクトeにreportメソッドを呼ばせる。
リスト5-3 reportメソッドはeに呼ばせる
e.report
最後にこのeを戻すようにしておけば、作成したオブジェクトをさらに他の処理に使うことができる。
リスト5-4 最後にe を戻すと便利かも
return e end
そうすれば、トップレベルではnewメソッドの代わりにcreate_and_reportメソッドを使って、やはり3行ですむ。デハ、report_cmpl.rbをリスト5-5に示す。
リスト5-5 report_cmpl.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 def self.create_and_report(name, cost) e=self.new(name, cost) e.report return e end end ###トップレベル### e1=Enemy.create_and_report("E-1", 5000) e2=Enemy.create_and_report("E-2", 3000) e3=Enemy.create_and_report("E-DX", 8500) #あとはe1, e2, e3を好きに使える
でも、これは愛子井オヤジが「@を二つも書いててダッセー」と言われたのにムカっと来て「世の中にはクラス変数もあるんだヨ」と言いたいがために書かされたプログラムだ。
「総費用を計算するんだ」ということをもっとハッキリさせるためには、クラス変数やクラスメソッドより、むしろ「費用を計算する機能を持つクラス」というのを作ったほうがいいかも知れない。
CostCalculatorという名前はどうだろう。
総費用は、そのCostCalculatorオブジェクトのインスタンス変数@totalにしちゃうのだ。
リスト5-6 クラスCostCalculatorの定義とinitializeメソッド。インスタンス変数@totalを0にしておく。
class CostCalculator def initialize @total=0 #総費用を初期化しておく end def total @total end
クラスCostCalculatorに、費用計算のための全てのメソッドを集めちゃうってのはどうだ。
するとメソッドreportやtotal_costはEnemyオブジェクトeを引数にとり、eが Enemyクラスのインスタンスメソッドを呼ぶ。
一方、
totalはCostCalculatorのインスタンス変数で機能する。
リスト5-7引数eをとるreportやtotal_cost
def report(e) puts "#{e.name}作成費用:#{e.cost}" total_cost(e) end def total_cost(e) @total+=e.cost puts "総費用:#{total}" end
メソッドcreate_and_reportも、CostCalculatorクラスのインスタンスメソッドになる。
リスト5-8 create_and_reportメソッドもインスタンスメソッドに
def create_and_report(name, cost) e=Enemy.new(name, cost) report(e) return e end
トップレベルでは、一度CostCalculatorクラスのオブジェクトcalcを作ってから、calcがcreate_and_reportメソッドを読んで戻った結果がそれぞれのEnemyオブジェクトになる。
以上、CostCalculatorクラスを使ったreport_another.rbをリスト5-9に示す。
リスト5-9 report_another.rb
#-*- coding: shift_jis -*- ###クラスEnemyの定義### class Enemy def initialize(name, cost) @name=name @cost=cost end def name @name end def cost @cost end def report end end ##費用計算専用クラス## class CostCalculator def initialize @total=0 #総費用を初期化しておく end def total @total end def report(e) puts "#{e.name}作成費用:#{e.cost}" total_cost(e) end def total_cost(e) @total+=e.cost puts "総費用:#{total}" end def create_and_report(name, cost) e=Enemy.new(name, cost) report(e) return e end end ###トップレベル### calc=CostCalculator.new e1=calc.create_and_report("E-1", 5000) e2=calc.create_and_report("E-2", 3000) e3=calc.create_and_report("E-DX", 8500) #クラスメソッドを使わない方法どっちにするかは、お好み次第だ。Enemyクラスを使うときは必ず費用を計算するーッ、費用の計算なしにEnemyオブジェクトの作成はありえない、というような場合はクラスメソッドやクラス変数を使うし、「人によっては費用を計算するが、本当に大事なのは費用のではなーいッ」とかいう場合は費用計算専用のクラスを別に作るのがいいだろう。