Skip to content

工厂方法模式

定义一个用于创建对象的接口,让子类决定实例化哪一个类。

适合的场景

  • 创建过程复杂(涉及多个步骤或条件)

  • 创建的对象可能有多种类型(多子类)

  • 希望解耦调用者和具体类的依赖关系

当你在代码中频繁地写 new 某个类,一旦要改某个类名、构造逻辑或切换不同实现, 就得到处找找改改,工厂模式的出现,就是为了——把“new”这件事交给一个“工厂”来处理,调用者不用关心怎么创建,只管要。

比如:

游戏中根据不同关卡,创建不同类型的敌人 → EnemyFactory!

UI里根据配置,生成按钮或滑条 → WidgetFactory!

基本结构

  1. 定义一个抽象产品(接口或基类)

  2. 每个具体产品都实现这个产品接口

  3. 定义一个抽象工厂类,提供“创建方法”接口

  4. 每个具体工厂类负责创建具体产品!

示例

csharp
// 抽象产品
public interface IEnemy
{
	void Attack();
}

// 具体产品 A
public class Slime : IEnemy
{
	public void Attack() => Console.WriteLine("Slime攻击!");
}

// 具体产品 B
public class Goblin : IEnemy
{
	public void Attack() => Console.WriteLine("Goblin突袭!");
}

// 抽象工厂
public abstract class EnemyFactory
{
	public abstract IEnemy CreateEnemy();
}

// 具体工厂 A
public class SlimeFactory : EnemyFactory
{
	public override IEnemy CreateEnemy() => new Slime();
}

// 具体工厂 B
public class GoblinFactory : EnemyFactory
{
	public override IEnemy CreateEnemy() => new Goblin();
}

// 使用
EnemyFactory factory = new GoblinFactory();
IEnemy enemy = factory.CreateEnemy();
enemy.Attack();

注意:

这只是传统工厂模式的标准实现,也有其他不同的工厂模式的实现,例如:

  • 用静态工厂方法来构造对象

  • 用字符串匹配来构造对象

在游戏开发中,为了灵活性和性能,通常还会结合资源管理器、场景实例化等方式来处理。

GDScript 示例

gdscript
# 抽象敌人
class Enemy:
	func attack():
		pass

# 具体敌人
class Slime extends Enemy:
	func attack():
		print("Slime攻击!")

class Goblin extends Enemy:
	func attack():
		print("Goblin突袭!")

# 敌人工厂
class EnemyFactory:
	static func create_enemy(enemy_type: String) -> Enemy:
		match enemy_type:
			"slime":
				return Slime.new()
			"goblin":
				return Goblin.new()
			_:
				push_error("未知敌人类型: %s" % enemy_type)
				return null
	
# 使用            
func _ready():
	var enemy = EnemyFactory.create_enemy("goblin")
	enemy.attack()