我想创建一个接受类类型并返回构造函数的工厂函数,以便我可以使用该构造函数稍后创建该类的实例。
想象一下,我有两个类,Apple和Orange,它们都是Fruit的子类。它们需要使用unknownNumber
初始化,我稍后才能知道。
class Apple: Fruit {
init(unknownNumber: Int) {
...
}
}
class Orange: Fruit {
init(unknownNumber: Int) {
...
}
}
我想创建一个接受Class类型的工厂函数,以便稍后我可以使用unknownNumber调用此函数并初始化Fruit的特定子类。
//concept:
func makeFruit(typeOfFruit) -> (Int) -> Fruit {
return { (unknownNumber: Int) -> Fruit in
return typeOfFruit(unknownNumber)
}
}
要创建一个orangeFactory,我可以这样做:
let orangeFactory = makeFruit(Orange)
// then at a later time when I have the unknown number
let orangeInstance = orangeFactory(unknownNumber)
我知道可以选择简单地使unknownNumber
成为一个惰性变量,但在我的具体情况下,unknownNumber
不仅仅是一个数字而且还涉及其他过程,所以我会这样做喜欢只在我拥有一切可用时创建对象,以保持结构简单。
在Swift中这样的事情可能吗?我已经在网上研究了一段时间,似乎无法找到任何直接的答案。任何帮助将不胜感激!
答案 0 :(得分:6)
让我们倒退。在makeFruit
函数中,您需要将typeOfFruit
参数声明为Fruit
超类的元类型,并明确引用初始化程序:
func makeFruit(typeOfFruit: Fruit.Type) -> (Int) -> Fruit {
return { (unknownNumber: Int) -> Fruit in
return typeOfFruit.init(unknownNumber: unknownNumber)
}
}
您只能访问元类型的required
初始值设定项,因此init
需要标记为:
class Fruit {
required init(unknownNumber: Int) {
// ...
}
}
剩下的就应该工作:
let orangeMaker = makeFruit(Orange.self)
let tenOranges = orangeMaker(10)
答案 1 :(得分:1)
如果您打算将班级本身用作工厂参赛作品的标识符,那么您实际上并不需要工厂。工厂模式在任意标识符和对应的对象类之间创建间接。
在Swift中执行此操作的一种简单方法是使用字典:
var fruitFactory:[String:Fruit.Type] = [:]
fruitFactory["Apple"] = Apple.self
fruitFactory["Orange"] = Orange.self
fruitFactory["Banana"] = Fruit.self
fruitFactory["Grape"] = Fruit.self
let tenOranges = fruitFactory["Orange"]!.init(unknownNumber:10)
请注意,您需要将Fruit类中的初始化程序标记为必需,才能使其正常工作。
答案 2 :(得分:0)
您可以将Fruit
声明为公开所需init
方法的协议,并使用Switf中的泛型支持:
protocol Fruit {
init(unknownNumber: Int)
}
class Apple: Fruit {
required init(unknownNumber: Int) {
}
}
class Orange: Fruit {
required init(unknownNumber: Int) {
}
}
func makeFruit<T: Fruit>(cls: T.Type) -> Int -> T {
return { T(unknownNumber: $0) }
}
makeFruit(Apple.self)(10) // returns an Apple
makeFruit(Orange.self)(15) // returns an Orange
由于makeFruit
函数的结果与cls
参数指定的类型相同,因此也可以使您输入类型安全性。
请注意,这不是工厂功能,而只是转发功能。但你可以更进一步,为某些成果定制makeFruit
,这就是使它成为工厂功能的原因:
class Apple: Fruit {
required init(unknownNumber: Int) {
}
init(color: String, unknownNumber: Int) {
}
}
func makeFruit<T: Fruit>(cls: T.Type) -> Int -> T {
return { T(unknownNumber: $0) }
}
func makeFruit(cls: Apple.Type) -> Int -> Apple {
return { Apple(color: "red", unknownNumber: $0) }
}
makeFruit(Orange.self)(15) // an Orange
makeFruit(Apple.self)(10) // a red Apple
假设Apple
类有一个接受颜色的初始值设定项,我们可以覆盖此特定类的makeFruit
并传递默认颜色(或者可能是计算出的颜色,具体取决于工厂规格) 。这不会失去使用Swift在您身上增长的类型安全性。