I'd like to create a factory function that takes in an class type and returns a constructor, so that I can use that constructor to create an instance of that class later.
Imagine I have two classes, Apple and Orange, which are both subclasses of Fruit. They need to be initialized with an unknownNumber
which I will only know about later.
class Apple: Fruit {
init(unknownNumber: Int) {
...
}
}
class Orange: Fruit {
init(unknownNumber: Int) {
...
}
}
I'd like to create a factory function that takes in a Class type, so that I can later call this function and initialize the specific subclass of Fruit, with the unknownNumber.
//concept:
func makeFruit(typeOfFruit) -> (Int) -> Fruit {
return { (unknownNumber: Int) -> Fruit in
return typeOfFruit(unknownNumber)
}
}
To create an orangeFactory, then, I can do:
let orangeFactory = makeFruit(Orange)
// then at a later time when I have the unknown number
let orangeInstance = orangeFactory(unknownNumber)
I am aware of the option of simply making the unknownNumber
a lazy variable, but in my specific case the unknownNumber
is not just a number and it involves other processes, so I'd like to only create the object when I have everything available, to keep the structure simple.
Is something like this possible in Swift? I've been researching for a while online and couldn't seem to find any direct answers. Any help would be greatly appreciated!
Let's work backwards. In your makeFruit
function, you'll need to declare the typeOfFruit
parameter as a metatype of your Fruit
superclass and explicitly reference the initializer:
func makeFruit(typeOfFruit: Fruit.Type) -> (Int) -> Fruit {
return { (unknownNumber: Int) -> Fruit in
return typeOfFruit.init(unknownNumber: unknownNumber)
}
}
You can only access required
initializers on a metatype, so that init
needs to be marked as such:
class Fruit {
required init(unknownNumber: Int) {
// ...
}
}
The rest should just work:
let orangeMaker = makeFruit(Orange.self)
let tenOranges = orangeMaker(10)
If you are going to use the class itself as the identifier for a factory entry, you don't actually need a factory. The factory pattern creates an indirection between an arbitrary identifier and a corresponding class of object.
A simple way to do this in Swift is to use a dictionary:
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)
note that your initializer in the Fruit class needs to be marked as required for this to work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With