如何基于参数类型简化对象内的类初始化流程
优化基于类型参数的类初始化方案(替代冗余switch)
方案一:字典映射的工厂类(推荐)
这种方式用字典存储类型到实例创建逻辑的映射,既保留了switch的性能,又解决了冗余和扩展性问题,符合开闭原则(新增类型无需修改原有逻辑)。
实现步骤:
- 定义静态工厂类,维护类型与创建函数的映射字典:
public static class QuestObjectiveFactory { // 字典键为ObjectiveType,值为接收internalId并返回对应QuestObjective的委托 private static readonly Dictionary<ObjectiveType, Func<string, QuestObjective>> _objectiveCreators = new() { { ObjectiveType.Fetch, id => new ObjectiveFetch(id) }, { ObjectiveType.Gather, id => new ObjectiveGather(id) }, { ObjectiveType.Craft, id => new ObjectiveCraft(id) }, { ObjectiveType.Deliver, id => new ObjectiveDeliver(id) }, { ObjectiveType.Combat, id => new ObjectiveCombatEncounter(id) } }; public static QuestObjective Create(ObjectiveType objectiveType, string internalId) { if (_objectiveCreators.TryGetValue(objectiveType, out var creator)) { return creator(internalId); } throw new ArgumentOutOfRangeException(nameof(objectiveType), $"不支持的任务目标类型:{objectiveType}"); } }
- 改造原
GenerateQuest方法,调用工厂类创建实例:
protected Quest GenerateQuest(QuestConfiguration questConfiguration) { var objectives = new List<QuestObjective>(); foreach (var objectiveConfig in questConfiguration.ObjectiveConfigurations) { objectives.Add(QuestObjectiveFactory.Create(objectiveConfig.ObjectiveType, objectiveConfig.InternalId)); } return new Quest(objectives); }
优势:
- 性能与switch相当(字典查找为O(1))
- 新增任务目标类型时,只需在字典中添加一行映射,无需修改核心逻辑
- 代码结构清晰,职责分离
方案二:属性标记+反射(适合大量类型场景)
如果任务目标类型非常多,且希望避免手动维护映射字典,可以用反射+自定义属性的方式自动注册类型。
实现步骤:
- 定义标记属性,关联子类与
ObjectiveType:
[AttributeUsage(AttributeTargets.Class, Inherited = false)] public class ObjectiveTypeAttribute : Attribute { public ObjectiveType TargetType { get; } public ObjectiveTypeAttribute(ObjectiveType targetType) { TargetType = targetType; } }
- 给每个
QuestObjective子类添加该属性:
[ObjectiveType(ObjectiveType.Fetch)] public class ObjectiveFetch : QuestObjective { public ObjectiveFetch(string internalId) : base(internalId) { } } // 其他子类同理 // [ObjectiveType(ObjectiveType.Gather)] // public class ObjectiveGather : QuestObjective { ... }
- 实现工厂类,通过反射自动构建类型映射:
public static class QuestObjectiveFactory { private static readonly Dictionary<ObjectiveType, Type> _typeMapping = new(); static QuestObjectiveFactory() { // 扫描当前程序集中所有继承自QuestObjective且带有标记属性的子类 var objectiveTypes = typeof(QuestObjective).Assembly.GetTypes() .Where(t => t.IsSubclassOf(typeof(QuestObjective)) && !t.IsAbstract) .Select(t => new { ClassType = t, Attr = t.GetCustomAttribute<ObjectiveTypeAttribute>() }) .Where(x => x.Attr != null); foreach (var item in objectiveTypes) { _typeMapping.Add(item.Attr.TargetType, item.ClassType); } } public static QuestObjective Create(ObjectiveType objectiveType, string internalId) { if (_typeMapping.TryGetValue(objectiveType, out var targetType)) { // 假设所有子类都有接收string类型internalId的构造函数 return (QuestObjective)Activator.CreateInstance(targetType, internalId); } throw new ArgumentOutOfRangeException(nameof(objectiveType), $"不支持的任务目标类型:{objectiveType}"); } }
- 同样用改造后的
GenerateQuest方法调用工厂即可。
优势:
- 新增子类时只需添加属性,无需修改工厂逻辑
- 适合动态加载类型或类型数量极多的场景
注意:
- 反射初始化首次调用会有轻微性能开销,可通过提前预热优化
- 若子类构造函数参数变化,需同步调整反射逻辑
总结
如果类型数量不多,优先选方案一,兼顾性能和可维护性;如果类型数量庞大或需要动态扩展,再考虑方案二。两种方案都能彻底消除冗余的switch语句,让代码更易扩展。
内容的提问来源于stack exchange,提问作者vik
相关产品推荐
相关产品推荐

