I'm making a unit framework in Swift, which has measurement superclass and subclasses for different units, such as Mass and Volume. A feature is to allow the framework to correctly guess what unit it is created with and returning the correct class. example code:
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 to have a inherited class create an object of a specific subclass when initializing it?
Library is named Indus Valley and open source on GitHub
It's playing fast and loose with inheritance having the parent class know about its subclasses (very poor anti-pattern!) but this would 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
If you are creating subclass object in superclass then you app will crash because call to init method will be recursive. To test you can just create a hierarchy of class and try to create subclass object in super class.
You can solve this problem by using faced design pattern. Just you need to create one Interface class that internally use all other classes and create the object and return.
class UnitConverter {
class func measurement(unknownUnit: String) -> Measurement {
if unknownUnit == "kg" {
return Mass(unknownUnit)
} else if unknownUnit == "ml" {
return Volume(unknownUnit)
}
return Measurement(unknownUnit)
}
}
Depending on the use case, maybe this could 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
}
}
}
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