Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift:创建一个工厂函数,将类类型作为参数,并输出该类的构造函数_Swift_Inheritance_Constructor_Swift2 - Fatal编程技术网

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

Swift:创建一个工厂函数,将类类型作为参数,并输出该类的构造函数,swift,inheritance,constructor,swift2,Swift,Inheritance,Constructor,Swift2,我想创建一个接受类类型并返回构造函数的工厂函数,以便以后可以使用该构造函数创建该类的实例 假设我有两个类,Apple和Orange,它们都是水果的子类。它们需要用未知编号初始化,我以后才会知道 class Apple: Fruit { init(unknownNumber: Int) { ... } } class Orange: Fruit { init(unknownNumber: Int) { ... } } 我想创建一个

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

假设我有两个类,Apple和Orange,它们都是水果的子类。它们需要用
未知编号
初始化,我以后才会知道

class Apple: Fruit {
    init(unknownNumber: Int) {
        ...
    }
}

class Orange: Fruit {
    init(unknownNumber: Int) {
        ...
    }
}
我想创建一个接受类类型的工厂函数,以便稍后调用此函数并使用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
不仅仅是一个数字,它还涉及其他过程,因此我只希望在所有可用的情况下创建对象,以保持结构简单


这样的事情在斯威夫特可能吗?我在网上搜索了一段时间,似乎找不到任何直接的答案。任何帮助都将不胜感激

让我们反向工作。在
makeFruit
函数中,需要将
typeofruit
参数声明为
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)

您可以将
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

假设
Apple
类有一个接受颜色的初始值设定项,我们可以覆盖这个特定类的
makeFruit
,并传递一个默认颜色(或者一个计算的颜色,取决于工厂的规格)。这不会丢失Swift增加的类型安全性。

如果要将类本身用作工厂条目的标识符,实际上不需要工厂。工厂模式在任意标识符和相应的对象类之间创建间接寻址

在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)

请注意,水果类中的初始值设定项需要按要求进行标记,才能正常工作。

这是一个很好的答案。该方法看起来很简单,但也需要了解斯威夫特对象创建模型的许多小特性。我正在尝试这一点,并会让你知道很快如果它的工作!亲爱的选民们!请让我们知道,你认为这个答案有什么错。所有的答案(内特的,克里斯提克的,阿兰的)基本上使用相同的方法,所有的答案只是在小细节上有所不同。为什么克里斯蒂克的答案被否决了???请如果有人不喜欢某个答案,请告诉我们原因!嗨,克里斯蒂克,非常感谢你周到的回答。我以前没有考虑过使用泛型的方法,你的回答确实教会了我一些东西。我接受了内特的回答,因为它以一种非常直截了当的方式提供了我想要的,但我也非常感谢你的意见。很抱歉,有人否决了这个答案;我投了更高的票。非常感谢你的回答。一旦我了解了在Class.self上调用.init()的可能性,它就打开了许多大门!我同意你的方法是最简单的,但我觉得不得不选择内特的答案作为公认的答案,因为他完全回答了我的要求,而且它也能完美地工作!
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)