Swift中如何实现Class Type工厂?求代码优化方案
嘿,我来帮你捋清楚这个问题的解决方案~
核心疑问:能不能靠参数直接指定泛型类类型?
先给你个明确结论:在Swift这类静态类型语言里,没法直接用运行时的参数来动态指定泛型的T类型。因为泛型参数是编译阶段就确定好的,而你的objectType是运行时才会拿到的参数,两者的生命周期对不上,编译器没法提前推断出具体的T是什么。
不过别担心,我们有几种靠谱的优化方案可以实现你想要的效果——既不用写一堆switch,还能把setup()逻辑封装到create()里。
方案一:用类型映射表实现动态创建
这个思路很直接:先把objectType和对应的子类类型做个映射,然后根据参数从映射表里捞到具体类型,再调用创建方法。
第一步:给Builder加个支持传类型的方法
先扩展BaseObjectBuilder,让它能接收具体的子类类型来创建实例,顺便把setup()的逻辑移到这里:
extension BaseObjectBuilder { static func create<T: BaseObject>(type: T.Type) -> T { let instance = T() instance.setup() // 把原来单独调用的setup移到这里统一处理 return instance } }
第二步:建一个objectType到子类的映射表
假设你的objectType是个枚举(如果是字符串也一样),我们做个字典映射:
// 先定义你的objectType枚举 enum ObjectType { case type1, type2 } // 核心映射表:把每个ObjectType对应到具体的子类类型 private let objectTypeMap: [ObjectType: BaseObject.Type] = [ .type1: Object1.self, .type2: Object2.self ]
第三步:根据参数创建实例
现在就可以用参数动态创建了,还不用写switch:
func createObject(by type: ObjectType) -> BaseObject? { guard let targetType = objectTypeMap[type] else { return nil // 处理未知类型的情况 } // 调用扩展后的create方法,传入类型创建实例 let instance = BaseObjectBuilder.create(type: targetType) return instance }
这个方案简单直接,适合子类数量不多、变动不频繁的场景。
方案二:让子类自动注册到Builder
如果后续要加很多子类,不想每次都改映射表,那可以让每个子类自己“报名”到Builder里,更符合开闭原则。
第一步:给BaseObject加个注册协议
先定义一个协议,让子类能提供自己对应的objectType,并实现注册逻辑:
protocol ObjectRegisterable { static var objectType: ObjectType { get } static func register() } extension BaseObject: ObjectRegisterable { // 子类必须重写这个属性,不然会报错 static var objectType: ObjectType { fatalError("子类必须实现自己的objectType!") } static func register() { // 把自己注册到Builder的列表里 BaseObjectBuilder.register(type: self, for: objectType) } }
第二步:改造Builder维护注册列表
让Builder自己管理所有注册过的子类类型:
class BaseObjectBuilder { // 用字典存注册过的类型 private static var registeredTypes: [ObjectType: BaseObject.Type] = [:] // 提供注册方法 static func register(type: BaseObject.Type, for objectType: ObjectType) { registeredTypes[objectType] = type } // 根据objectType创建实例,顺便执行setup static func create(for objectType: ObjectType) -> BaseObject? { guard let targetType = registeredTypes[objectType] else { return nil } let instance = targetType.init() instance.setup() return instance } }
第三步:子类实现注册逻辑
每个子类只需要指定自己的objectType,并在合适的时机注册(比如初始化时,或者App启动时统一注册):
class Object1: BaseObject { // 指定自己对应的ObjectType override static var objectType: ObjectType { .type1 } // 初始化时自动注册,或者你也可以在AppDelegate里统一调用所有子类的register() override init() { super.init() Self.register() } // 原来的setup逻辑不变 override func setup() { // 你的子类初始化逻辑 } }
第四步:创建实例
现在创建就超简单了,直接传参数就行:
let myObject = BaseObjectBuilder.create(for: .type1)
这种方式的好处是,以后加新子类,只需要让子类实现objectType和注册逻辑,完全不用动Builder的代码,扩展性拉满。
补充:如果必须保留原有的泛型create方法
要是你的BaseObjectBuilder.create<T>()必须保持原来的泛型形式,那可以在拿到具体类型后,通过类型转换来适配:
func createSpecificObject<T: BaseObject>(by type: ObjectType) -> T? { guard let targetType = objectTypeMap[type] as? T.Type else { return nil } return BaseObjectBuilder.create() as? T }
不过这种方式需要调用方明确知道要返回的具体类型,灵活性稍差,适合特定场景使用。
内容的提问来源于stack exchange,提问作者Travis M.

