iOS开发:如何更优雅实例化遵循协议的类?
优雅解决iOS中基于字符串实例化协议类的分支问题
针对你当前用大量if/else分支实例化遵循unitLoadoutDataController协议类的问题,推荐以下几种无需分支的优雅方案:
方案一:使用名称-类映射字典(最推荐)
通过创建一个显示名称与对应类的映射字典,直接根据选中的名称取出类进行实例化,维护成本极低。
实现步骤:
- 定义映射字典(可放在类的初始化方法、常量文件或分类中):
// 示例:在当前类的viewDidLoad或初始化方法中定义 NSDictionary<NSString *, Class> *unitClassMap = @{ @"Heavy Intercessor Squad" : heavyIntercessorSquad.class, @"Eradicator Squad" : eradicatorSquad.class, // 依次添加剩余30个类的映射关系 };
- 实例化并赋值:
// 根据选中名称获取对应类 Class unitClass = unitClassMap[self.selectedUnit.name]; // 安全检查:确保类存在且遵循协议 if (unitClass && [unitClass conformsToProtocol:@protocol(unitLoadoutDataController)]) { self.squadToConfigure = [[unitClass alloc] init]; } else { // 处理异常情况,比如日志提示或默认实现 NSLog(@"未找到对应单元类或类不遵循协议:%@", self.selectedUnit.name); } // 执行后续配置逻辑 if (self.squadToConfigure) { [self.squadToConfigure setDefaultLoadout:self.selectedUnit.name unitId:newUnitId]; }
优点:
- 新增类仅需在字典中添加一行映射,无需修改实例化逻辑
- 代码简洁直观,彻底消除大量if/else分支
- 类型安全,通过协议检查避免实例化错误类
方案二:封装工厂类
如果后续实例化逻辑需要扩展(比如需要传入额外参数),可以将实例化逻辑封装到独立的工厂类中,进一步解耦业务代码。
实现示例:
- 创建工厂类:
@interface UnitFactory : NSObject /// 根据单元名称创建遵循unitLoadoutDataController协议的实例 + (id<unitLoadoutDataController>)createUnitWithName:(NSString *)unitName; @end @implementation UnitFactory + (id<unitLoadoutDataController>)createUnitWithName:(NSString *)unitName { NSDictionary<NSString *, Class> *classMap = @{ @"Heavy Intercessor Squad" : heavyIntercessorSquad.class, @"Eradicator Squad" : eradicatorSquad.class, // 其他类映射 }; Class unitClass = classMap[unitName]; if (unitClass && [unitClass conformsToProtocol:@protocol(unitLoadoutDataController)]) { return [[unitClass alloc] init]; } return nil; } @end
- 使用工厂类实例化:
self.squadToConfigure = [UnitFactory createUnitWithName:self.selectedUnit.name]; if (self.squadToConfigure) { [self.squadToConfigure setDefaultLoadout:self.selectedUnit.name unitId:newUnitId]; }
优点:
- 实例化逻辑集中管理,业务代码无需关心具体类的创建细节
- 便于后续扩展实例化规则(比如添加缓存、参数初始化等)
方案三:运行时动态类名转换(不推荐)
如果显示名称和类名有固定的转换规则,可以通过运行时API动态获取类,但这种方式依赖名称强绑定,风险较高。
实现示例:
// 将显示名称转换为类名(示例规则:去掉空格,首单词小写,后续单词首字母大写) - (NSString *)convertUnitNameToClassName:(NSString *)unitName { NSArray *words = [unitName componentsSeparatedByString:@" "]; NSMutableString *className = [NSMutableString string]; for (NSInteger i = 0; i < words.count; i++) { NSString *word = words[i]; if (i == 0) { [className appendString:[word lowercaseString]]; } else { [className appendString:[word capitalizedString]]; } } return className; } // 动态实例化 NSString *className = [self convertUnitNameToClassName:self.selectedUnit.name]; Class unitClass = NSClassFromString(className); if (unitClass && [unitClass conformsToProtocol:@protocol(unitLoadoutDataController)]) { self.squadToConfigure = [[unitClass alloc] init]; }
缺点:
- 依赖显示名称与类名的强绑定关系,一旦名称或类名修改容易出错
- 调试和维护成本高,无法直观看到所有映射关系
内容的提问来源于stack exchange,提问作者Doug Idle
相关产品推荐
相关产品推荐

