2015-05-25 15 views
5

Sto creando una struttura di unità in Swift, che ha superclasse di misurazione e sottoclassi per unità diverse, come Massa e Volume. Una funzionalità è consentire al framework di indovinare correttamente con quale unità è stato creato e restituire la classe corretta. codice di esempio:Crea l'inizializzatore per la superclasse restituisce una sottoclasse specifica?

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 

E 'possibile avere una classe ereditata creare un oggetto di una sottoclasse specifica durante l'inizializzazione è?

Biblioteca è chiamato Indus Valley e open source su GitHub

+0

Questo è sicuramente una limitazione fastidiosa di Swift 'non init' restituire un valore. – pkamb

risposta

0

Sta giocando a tira e molla con l'ereditarietà avendo la classe genitore conoscere le sue sottoclassi (molto scarso anti-modello!), Ma questo dovrebbe funzionare ...

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

Se si crea un oggetto sottoclasse in superclasse, l'app si arresterà in modo anomalo perché la chiamata al metodo init sarà ricorsiva. Per testare puoi semplicemente creare una gerarchia di classi e provare a creare oggetti di sottoclasse in super-classe.

È possibile risolvere questo problema utilizzando il modello di progettazione fronte. È sufficiente creare una classe di interfaccia che utilizzi internamente tutte le altre classi e crei l'oggetto e restituisca.

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

Questo è vero solo se la sottoclasse chiama lo * stesso * inizializzatore del genitore. Tuttavia, se le sottoclassi chiamano un inizializzatore speciale (ad esempio privato) della superclasse, esso non verrà ripetuto all'infinito. È così che funzionava in Obj-C. – devios1

1

A seconda del caso d'uso, forse questo potrebbe essere una valida alternativa:

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

Sì, questa è la mia soluzione attuale, mi chiedevo se qualcuno ne avesse per gli inizializzatori :) – hakonbogen

Problemi correlati