In Swift, I want to make my base class static method return its subclass objects when the static method is called from a subclass.
When returning one subclass object, I can make it possible by using init(). But when returning multiple subclass objects, init() can not be used.
And I want to not only just return subclass objects from the parent static method, but also to implement some logic other than instantiation in the parent static method, and make the static method of each subclass inherit the parent's static method behavior.
I have 3 sub-classes. So, I don't want to write the same code in the static methods of 3 sub-classes. How should I do?
If possible, I want to use the static method instead of init() to return a single subclass object, too.
class Base {
func f() {
print("base class")
}
// this does not works. it creates a base class object.
static func createSubclassObject() -> Base {
return Base()
}
// this works. it creates a subclass object.
init() {
}
// this does not work. base class objects are created.
static func createSubclassObjects(count: Int) -> [Base] {
var objects = [Base]()
for _ in 0 ..< count {
objects.append(Base())
}
return objects
}
/* probably I need something like this. but this code generates a compile error
static func createSubclassObjects(count: Int) -> [Self] {
var objects = [Self]()
for _ in 0 ..< count {
objects.append(Self())
}
return objects
}
*/
// generic also does not work. this returns a base class object.
static func createSubclassObjectByGeneric<T: Base>() -> T {
return T()
}
}
class Sub: Base {
override func f() {
print("sub class")
}
}
print(Sub().f())
// sub class・
print(Sub.createSubclassObject().f())
// base class
Sub.createSubclassObjects(count: 2).forEach {
print($0.f())
}
// base class
// base class
print(Sub.createSubclassObjectByGeneric().f())
// base class
CodePudding user response:
You need to return Self
, not Base
.
static func createSubclassObject() -> Self {
.init()
}
required init() { }
Also, don't use a for loop. There is an array initializer premade for what you're doing.
static func createSubclassObjects(count: Int) -> [Base] {
.init(repeating: createSubclassObject(), count: count)
}
CodePudding user response:
The following code works. But I think there should be better solutions because I don't want to define class func sub()
in the parent class and override class func sub()
in each sub class.
EDIT: See the Jessy's answer, which is the better solution.
class Base {
func f() {
print("base class")
}
static func createSubclassObjects(count: Int) -> [Base] {
var objects = [Base]()
for _ in 0 ..< count {
//objects.append(Base())
objects.append(Self.sub())
}
return objects
}
class func sub() -> Base {
Base()
// or use fatalError() if you don't need to call createSubclassObjects(count: Int) from the base class
}
}
class Sub1: Base {
override func f() {
print("sub1 class")
}
override class func sub() -> Base {
Sub1()
}
}
class Sub2: Base {
override func f() {
print("sub2 class")
}
override class func sub() -> Base {
Sub2()
}
}
Base.createSubclassObjects(count: 2).forEach {
print($0.f())
}
// base class
// base class
Sub1.createSubclassObjects(count: 2).forEach {
print($0.f())
}
// sub1 class
// sub1 class
Sub2.createSubclassObjects(count: 2).forEach {
print($0.f())
}
// sub2 class
// sub2 class