Do an initializer for a superclass return a specific subclass?

I am creating a single structure in Swift that has a measuring superclass and subclasses for different units such as mass and volume. The peculiarity is to allow the framework to correctly guess which block it was created from and return the correct class. code example:

class Measurement { var unitString : String init(unknownUnit: String) { // checks if the unit is either Volume or Mass, and returns an instance of that class } } class Volume : Measurement { init(unitString: String) { } } class Mass : Measurement { init(unitString: String) { } } let mass = Mass("kg") // class: Mass let volume = Volume("ml") // class: Volume let shouldBeVolume = Measurement("ml") // class: Volume let shouldBeMass = Measurement("kg") // class: Mass 

Is it possible for an inherited class to create an object of a particular subclass when it is initialized?

The library is called Indus Valley and is open source on GitHub

+5
source share
3 answers

He plays quickly and freely with inheritance, having a parent class, about his subclasses (very bad anti-pattern!), But it will work ...

 class Measurement { var unitString : String class func factory(unknownUnit: String) -> Measurement { if unknownUnit == "kg" { return Mass(myUnit: unknownUnit) } else { // Random default, or make func return Measurement? to trap return Volume(myUnit: unknownUnit) } } init(myUnit: String) { // checks if the unit is either Volume or Mass, and returns an instance of that class self.unitString = myUnit } } class Volume : Measurement { } class Mass : Measurement { } let mass = Mass(myUnit: "kg") // class: Mass let volume = Volume(myUnit: "ml") // class: Volume let shouldntBeVolume = Measurement(myUnit: "ml") // class: Measurement let shouldntBeMass = Measurement(myUnit: "kg") // class: Measurement let isVolume = Measurement.factory("ml") // class: Volume let shouldBeMass = Measurement.factory("kg") // class: Mass 
0
source

If you create a subclass object in a superclass, then the application will break because the invocation of the init method will be recursive. To check, you can simply create a class hierarchy and try to create a subclass object in the superclass.

You can solve this problem by using a pattern with a picture. You just need to create one interface class that internally uses all other classes and creates an object and returns.

 class UnitConverter { class func measurement(unknownUnit: String) -> Measurement { if unknownUnit == "kg" { return Mass(unknownUnit) } else if unknownUnit == "ml" { return Volume(unknownUnit) } return Measurement(unknownUnit) } } 
+1
source

Depending on the use case, this may be a suitable alternative:

 enum Measurement { case Mass case Volume static func fromUnit(unit:String) -> Measurement? { switch unit { case "mg", "g", "kg": return Mass case "ml", "dl", "l": return Volume default: return nil } } } 
+1
source

All Articles