テンプレートメソッドパターン
CoddyのGDScriptジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 53/65。
Template Method パターンは、親クラスでアルゴリズムの手順の順序を固定し、各サブクラスがその手順の一部を埋められるようにします。手順を実行する親クラスのメソッドがテンプレートメソッドです。
# level.gd
@abstract
class_name Level
extends RefCounted
func play() -> void:
print("Loading ", get_level_name())
spawn_enemies()
print("Level complete!")
@abstract func get_level_name() -> String
@abstract func spawn_enemies() -> voidplay()はテンプレートです。すべてのレベルはこの順序で読み込まれ、敵を出現させ、完了します。異なる手順は抽象的なので、すべてのサブクラスで実装する必要があります。
# forest_level.gd
class_name ForestLevel
extends Level
func get_level_name() -> String:
return "Forest"
func spawn_enemies() -> void:
print("3 wolves appear")CaveLevel も同じように記述し、名前は "Cave"、5 bats appear とします。
# main.gd
var levels: Array[Level] = [ForestLevel.new(), CaveLevel.new()]
for level in levels:
level.play()Loading Forest
3 wolves appear
Level complete!
Loading Cave
5 bats appear
Level complete!ステップには、親クラスでデフォルトの実装を定義し、サブクラスでオーバーライドできるものもあります。このようなオプションのステップはフックと呼ばれます。
# level.gd
func play() -> void:
print("Loading ", get_level_name())
spawn_enemies()
if has_boss():
print("The boss arrives")
print("Level complete!")
func has_boss() -> bool:
return falsehas_boss() をオーバーライドして true を返すレベルだけが、ボスの行を表示します。サブクラスは手順を記述し、親クラスがそれらを実行するタイミングを決定するため、サブクラスでは play() を変更せず、すべてのレベルが同じ順序に従います。
チャレンジ
中級ゲームは同じ手順でスコアを2つの形式で出力します。行は、"name"と"score"を持つ辞書です。
exporter.gdでは、テンプレートメソッドexport_rows(rows)を記述します。まずheader()を出力し、次に各行についてformat_row(row)を出力し、その後footer(rows)を出力します。ヘッダーまたはフッターが空文字列の場合は出力しません。フックのheader()とfooter()はデフォルトで""を返し、format_row()は抽象メソッドです。CsvExporter:ヘッダーはname,scoreで、行はAda,12です。フッターはありません。ListExporter:ヘッダーはなく、行は* Ada scored 12です。フッターは行数を含むPlayers: Nです。
用意されているコードは、形式(csvまたはlist)、続く行数、そして1行につき1つのNAME SCORE行を読み取ります。Ada 12とBo 7を指定したlistの場合、出力は次のとおりです。
* Ada scored 12
* Bo scored 7
Players: 2コードはexporter.gd、csv_exporter.gd、list_exporter.gdに記述します。main.gdには用意されている入出力コードが含まれており、編集できません。
自分で試してみよう
extends Node
func _ready():
# 提供された入出力コード: そのままにしてください
var style := OS.read_string_from_stdin()
var rows: Array = []
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
rows.append({"name": parts[0], "score": int(parts[1])})
var exporter: Exporter = CsvExporter.new()
if style == "list":
exporter = ListExporter.new()
exporter.export_rows(rows)
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: GDScriptオンラインコンパイラ