クラス変数なるもの-5. お手製クラスメソッドはいかが-

「フツーはオブジェクトを生成して、必要な設定をする」程度に思われている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オブジェクトの作成はありえない、というような場合はクラスメソッドやクラス変数を使うし、「人によっては費用を計算するが、本当に大事なのは費用のではなーいッ」とかいう場合は費用計算専用のクラスを別に作るのがいいだろう。

前へ

「クラス変数なるもの」トップへ

目次へ

このページの目次へ