ファクトリーパターン
CoddyのGDScriptジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 47/65。
ファクトリーパターンでは、どのクラスを作成するかの選択を一か所に集約します。プログラムのほかの部分はファクトリに「ゴブリンを1体」と要求してオブジェクトを受け取るため、クラス名 Goblin を指定する必要はありません。
生成物は親クラスを共有しているため、それらを使用するコードはどの生成物でも動作します。
# enemy.gd
class_name Enemy
extends RefCounted
var hp := 10
func attack() -> String:
return "The enemy waits"# goblin.gd
class_name Goblin
extends Enemy
func attack() -> String:
return "The goblin stabs"# orc.gd
class_name Orc
extends Enemy
func attack() -> String:
return "The orc smashes"ファクトリーは、名前をオブジェクトに変換する static func を持つクラスです。戻り値の型は親クラスなので、あらゆる種類の敵を返すことができ、知らない名前に対しては null を返します:
# enemy_factory.gd
class_name EnemyFactory
extends RefCounted
static func create(kind: String) -> Enemy:
match kind:
"goblin":
return Goblin.new()
"orc":
return Orc.new()
return null# main.gd
for kind in ["orc", "goblin", "slime"]:
var enemy := EnemyFactory.create(kind)
if enemy == null:
print("Unknown enemy: ", kind)
else:
print(enemy.attack())The orc smashes
The goblin stabs
Unknown enemy: slimeこのような名前は、通常データから取得されます。スポーンテーブル、レベルファイル、プレイヤーが入力したコマンドなどです。クラスへの対応付けを行うのはファクトリーだけなので、Dragonを追加するには、新しいファイルを1つ作成し、matchに新しい分岐を1つ追加するだけです。
ファクトリーはオブジェクトを返す前に設定することもできるため、呼び出し元は誰でもすぐに使える敵を受け取れます。
static func create_boss(kind: String, level: int) -> Enemy:
var boss := create(kind)
if boss != null:
boss.hp = 100 * level
return bossEnemyFactory.create_boss("orc", 3)はHPが300のOrcを返します。
チャレンジ
中級スポーンテーブルには敵とレベルが記載されています。Enemy(enemy.gd)とそのサブクラスのGoblin(goblin.gd)はすでに記述されています。残りを完成させましょう。
orc.gdでは、コンストラクターの_init(level)から親コンストラクターに名前Orc、HPの25 * level、ダメージの4 + levelを渡します。Goblinと同じ方法です。enemy_factory.gdでは、static func create(kind, level)が、goblinにはGoblinを、orcにはOrcを返すようにします。どちらも指定されたレベルで作成します。名前の大文字・小文字は区別されません(ORCはorcです)。それ以外の名前にはnullを返します。
用意されているコードは、後に続くスポーン数を読み取り、各スポーンについてKIND LEVELの行を1行ずつ読み込み、各敵またはUnknown enemy: KINDを出力した後、スポーンした敵の数を出力します。goblin 2、Orc 3、slime 1の場合、出力は次のとおりです。
Goblin: 20 HP, 4 damage
Orc: 75 HP, 7 damage
Unknown enemy: slime
Spawned: 2コードはenemy_factory.gdとorc.gdに記述します。main.gdには用意されている入出力コードがあり、編集できません。
自分で試してみよう
extends Node
func _ready():
# 用意された入出力コード:そのままにしてください
var spawned := 0
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
var enemy := EnemyFactory.create(parts[0], int(parts[1]))
if enemy == null:
print("Unknown enemy: ", parts[0])
else:
spawned += 1
print(enemy.describe())
print("Spawned: ", spawned)
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: GDScriptオンラインコンパイラ