C#控制台游戏地图对象创建:如何解耦工厂模式实现?
C# 游戏对象工厂解耦方案
问题场景
我正在开发一款C#控制台游戏,需读取文件生成的地图。读取文件内容为字符串后,逐个解析字符并通过工厂模式创建对应对象。现有基类Object,派生了Box、Wall、Grass、Tree等子类,每个子类通过重写只读属性Model定义游戏显示字符,且在构造函数中设置MapCharacter对应文件中的标识字符。当前工厂类使用switch语句根据MapCharacter创建对象,新增子类时需修改switch,存在耦合问题。曾考虑用反射获取子类信息,但认为该方案不够优雅,希望寻求更优的解耦实现方式。
方案1:静态注册机制(可控性强,无反射)
让每个子类自行注册到全局映射表,工厂直接从映射表获取创建逻辑,新增子类时仅需修改子类代码,无需改动工厂。
修改基类,添加注册逻辑
public abstract class Object { public abstract char Model { get; } public string Name { get; protected set; } public char MapCharacter { get; protected set; } // 其他属性(Colors、Destructible等)省略... public abstract void OnDestroy(); // 全局映射表:地图字符 → 对象创建委托 private static readonly Dictionary<char, Func<Object>> _objectCreators = new(); // 子类调用的注册方法 protected static void RegisterObject(char mapChar, Func<Object> creator) { if (!_objectCreators.ContainsKey(mapChar)) { _objectCreators.Add(mapChar, creator); } } // 供工厂调用的实例创建入口 public static Object CreateFromMapChar(char mapChar) { _objectCreators.TryGetValue(mapChar, out var creator); return creator?.Invoke(); } }
子类添加静态构造函数完成注册
public class Box : Object { public override char Model => '■'; // 静态构造函数,程序启动时自动执行注册 static Box() { RegisterObject('B', () => new Box()); } public Box() { Name = "box"; MapCharacter = 'B'; Colors = new List<ConsoleColor> { ConsoleColor.DarkYellow }; Destructible = true; Passable = false; SeeThrough = false; Health = 200; } public override void OnDestroy() { } }
简化工厂类
public class ObjectFactory : IObjectFactory { public Object GetObject(char mapCharacter) { return Object.CreateFromMapChar(mapCharacter); } }
方案2:特性标记 + 启动扫描(低耦合,少量反射)
用特性标记子类对应的地图字符,程序启动时一次性扫描所有子类构建映射表,比直接在工厂中反射创建更高效。
定义映射特性
[AttributeUsage(AttributeTargets.Class, Inherited = false)] public class MapCharacterAttribute : Attribute { public char Character { get; } public MapCharacterAttribute(char character) { Character = character; } }
子类添加特性标记
[MapCharacter('B')] public class Box : Object { public override char Model => '■'; public Box() { Name = "box"; Colors = new List<ConsoleColor> { ConsoleColor.DarkYellow }; Destructible = true; Passable = false; SeeThrough = false; Health = 200; } public override void OnDestroy() { } }
工厂类实现扫描与创建
public class ObjectFactory : IObjectFactory { private readonly Dictionary<char, Type> _objectTypes = new(); public ObjectFactory() { // 扫描当前程序集中所有继承自Object的非抽象类 var objectTypes = typeof(Object).Assembly.GetTypes() .Where(t => typeof(Object).IsAssignableFrom(t) && !t.IsAbstract); foreach (var type in objectTypes) { var attr = type.GetCustomAttribute<MapCharacterAttribute>(); if (attr != null && !_objectTypes.ContainsKey(attr.Character)) { _objectTypes.Add(attr.Character, type); } } } public Object GetObject(char mapCharacter) { if (_objectTypes.TryGetValue(mapCharacter, out var type)) { return (Object)Activator.CreateInstance(type); } return null; } }
方案3:依赖注入容器(适合大型项目)
如果项目已使用DI容器(如Autofac、Microsoft.Extensions.DependencyInjection),可将所有Object子类注册到容器,工厂从容器获取实例,进一步解耦创建逻辑。
注册服务(以Microsoft DI为例)
var services = new ServiceCollection(); // 注册所有Object子类为瞬时服务 services.AddTransient<Box>(); services.AddTransient<Tree>(); services.AddTransient<Wall>(); services.AddTransient<Grass>(); // 注册工厂 services.AddSingleton<IObjectFactory, ObjectFactory>(); var provider = services.BuildServiceProvider();
DI版工厂实现
public class ObjectFactory : IObjectFactory { private readonly IServiceProvider _serviceProvider; private readonly Dictionary<char, Type> _objectTypeMap = new() { {'B', typeof(Box)}, {'T', typeof(Tree)}, {'W', typeof(Wall)}, {'G', typeof(Grass)} }; public ObjectFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public Object GetObject(char mapCharacter) { if (_objectTypeMap.TryGetValue(mapCharacter, out var type)) { return (Object)_serviceProvider.GetService(type); } return null; } }
若想进一步解耦映射表,可结合方案2的特性扫描逻辑,在工厂构造函数中自动生成_objectTypeMap,无需手动维护字典。
内容的提问来源于stack exchange,提问作者dragnash
相关产品推荐
相关产品推荐

