2015-05-25 6 views
5

Ich mache eine Einheit Framework in Swift, die Messung Oberklasse und Unterklassen für verschiedene Einheiten, wie Masse und Volumen hat. Eine Funktion besteht darin, dem Framework zu ermöglichen, richtig zu erraten, mit welcher Einheit es erstellt wurde, und die richtige Klasse zurückzugeben. Beispielcode:Make Initialisierung für Oberklasse eine bestimmte Unterklasse zurückgeben?

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 

Ist es möglich, eine vererbte Klasse erstellen ein Objekt einer bestimmten Unterklasse zu haben, wenn es zu initialisieren?

Bibliothek ist Indus Valley und Open Source auf GitHub namens

+0

Dies ist definitiv eine lästige Beschränkung von Swift 'init' keinen Wert zurück. – pkamb

Antwort

0

Es ist schnell und locker mit Vererbung spielt die Elternklasse über ihre Unterklassen kennen, die (sehr schlecht anti-Muster!), Aber dies funktionieren würde ...

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 
1

Wenn Sie ein Unterklasse-Objekt in der Oberklasse erstellen, stürzt Ihre App ab, weil der Aufruf der init-Methode rekursiv ist. Um zu testen, können Sie einfach eine Klassenhierarchie erstellen und versuchen, ein Unterklassenobjekt in der Superklasse zu erstellen.

Sie können dieses Problem lösen, indem Sie Entwurfsmuster verwenden. Sie müssen nur eine Interface-Klasse erstellen, die intern alle anderen Klassen verwendet und das Objekt erstellt und zurückgibt.

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

     return Measurement(unknownUnit) 
    } 
} 
+0

Das ist nur wahr, wenn die Unterklasse den * self * Initialisierer des Elterns aufruft. Wenn die Unterklassen jedoch einen speziellen (z. B. privaten) Initialisierer der Oberklasse aufrufen, wird sie nicht unendlich rekursiv. So funktionierte es in Obj-C. – devios1

1

Je nach Anwendungsfall, vielleicht ist dies eine geeignete Alternative sein könnte:

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 
     } 
    } 
} 
+0

Ja, das ist meine aktuelle Lösung, fragte mich, ob jemand irgendwelche für Initialisierer hatte :) – hakonbogen

Verwandte Themen