Swift:创建一个将类类型作为参数的工厂函数,并输出该类

时间:2016-01-12 21:21:11

标签: swift inheritance constructor swift2

我想创建一个接受类类型并返回构造函数的工厂函数,以便我可以使用该构造函数稍后创建该类的实例。

想象一下,我有两个类,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中这样的事情可能吗?我已经在网上研究了一段时间,似乎无法找到任何直接的答案。任何帮助将不胜感激!

3 个答案:

答案 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在您身上增长的类型安全性。