ゲーム開発のためのオブジェクト指向(Template Method / Strategy)

投稿者: | 2012年5月25日

テンプレートメソッドとストラテジーメソッド

テンプレートメソッドとは、細かい部分でのアルゴリズムの交換を容易にする方法です。

例えば、シミュレーションRPGのユニットを実装してみます。Pythonで実装すると以下のようになります。

<unit.py>
class Unit:
	def execute(self):
		self.analize()
		self.move()
		self.action()

このクラスは、analize()→move()→action()というメソッドの呼び出し順を規定しているだけです。なので、このクラスだけでは役に立ちません。各メソッドの実装は、このクラスの派生クラス(継承先クラス)で行います。

<fighter.py>
from unit import Unit

class Fighter(Unit):
	def analize(self):
		print "Fighter analizing..."
	def move(self):
		print "Fighter moving..."
	def action(self):
		print "Fighter attack!"

まずは「戦士」クラス。

<magician.py>
from unit import Unit

class Magician(Unit):
	def analize(self):
		print "Magician analizing..."
	def move(self):
		print "Magician moving..."
	def action(self):
		print "Magician use Fire Magic!"

続いて、「魔法使い」クラス。

<priest.py>
from unit import Unit

class Priest(Unit):
	def analize(self):
		print "Priest analizing..."
	def move(self):
		print "Priest moving..."
	def action(self):
		print "Priest use Recovery Magic!"

最後に、「僧侶」クラスをこのように定義します。

こうすると、何がうれしいのかというと、各ユニットを操作する場合、execute()メソッドを呼ぶだけで、勝手に動いてくれるからです。

<main.py>
from fighter import Fighter
from magician import Magician
from priest import Priest

fighter = Fighter()
magician = Magician()
priest = Priest()

print "---Turn Begin---"
print "Fighter's Turn"
fighter.execute()
print "Magician's Turn"
magician.execute()
print "Priest's Turn"
priest.execute()
print "---Turn End---"

例えば、このような使い方をします。

で、

---Turn Begin---
Fighter's Turn
Fighter analizing...
Fighter moving...
Fighter attack!
Magician's Turn
Magician analizing...
Magician moving...
Magician use Fire Magic!
Priest's Turn
Priest analizing...
Priest moving...
Priest use Recovery Magic!
---Turn End---

実行結果はこうなります。

その後もし各ユニットのアルゴリズムを修正したくなった場合には、派生クラスのメソッドを修正するだけでよいので、とても楽になります。

注意する点としては、ある程度実装が終わったところで、「execute()メソッド実行する順番を変えてはいけない」ということです。もし、修正を行うと、各派生クラスにも影響が及んでしまいます。

ということで、execute()メソッドの仕様は慎重に決めましょう! というのが、テンプレートメソッドです。

続いて、ストラテジーメソッドですが、実はテンプレートメソッドとほとんど同じです。違いは、「全体のアルゴリズムを動的に交換する」ということです。

具体的には、派生クラスにおいて、excute()メソッドそのものの記述を行います。こちらのほうが「柔軟性」はありますが、あまり色々やらせると派生クラスが大きくなってしまうのが注意点ですね。