2017-10-22 5 views
0

Ich implementiere Vars in Kotlin, die Out-of-Bounds-Input von bestimmten ihrer Benutzer erhalten konnten. Ich möchte optional (nur für die Eingabe von diesen nicht vertrauenswürdigen Benutzern) einen validierenden Konstruktor aufrufen können, der null zurückgeben kann, und dann den Elvis-Operator verwenden, um im Falle einer ungültigen Eingabe Standardwerte anzugeben, wie in: var myFoo = Foo.fromInt(i) ?: 1. Ich bin derzeit eine Begleiter Objektmethode mit der Eingabe bestätigen:Wie implementiert man einen validierenden Konstruktor in Kotlin?

open class Foo(val x:Int) { // relies on valid x in 1..3 
    companion object { 
    fun fromInt(x: Int): Foo? = if (x in 1..3) Foo(x) else null 
    } 
} 
class Bar(x:Int) : Foo(x) 

fun main(args:Array<String>) { 
    println(Foo.fromInt(2)) // Foo(2) 
    println(Foo.fromInt(20)) // null 
    // println(Bar.fromInt(2)) 
    // would like Bar(2) but as expected, companion isn't inherited 
} 

Wenn ich Unterklasse Foo, ich weiß, ich habe das Begleitobjekt neu zu erstellen. Ich habe versucht, den Begleiter von einer abstrakten Klasse zu erben; Der Aufruf von Foo(x) verweist jedoch immer noch auf Foo und nicht auf Bar, es sei denn, ich überschreibe fromInt in den Companern jeder Unterklasse. Gibt es eine bessere oder mehr Kotlin-idomatic Weise, mit dieser Art von Muster eines validierenden Konstruktors umzugehen, der null zurückgeben kann, anstatt das angeforderte Objekt zu erstellen?

Antwort

1

können Sie einfach einen einzigen Konstruktor verwenden und immer sein Argument bestätigen x und weisen Sie wie hier auf eine Eigenschaft:

open class Foo (x: Int) { // relies on valid x in 1..3 
    val x: Int = if (x in 1..3) x else 1 
} 

class Bar(x: Int) : Foo(x) 

nun den Konstruktor mit einem Wert aufrufen, die nicht in Reichweite ist, wird ein Standard Foo ist erstellt, das ist im Grunde das, was Sie haben wollten, denke ich. Meiner Meinung nach wäre es besser, wenn Sie einen IllegalArgumentException anstatt einen Standard hinter den Kulissen zu werfen. Was denken Sie?

+0

Ich habe das auch ausprobiert. Die Herausforderung besteht darin, dass "Foo" (in meiner App) ein Feldtyp in einer Datenbank ist. Daher gibt es in jedem Datensatz mehr als 10 Felder dieses Typs, und einige haben bei einem fehlgeschlagenen Validierungsvorgang andere Standardwerte. Tatsächlich konnten sogar diese 10+ in ein paar Gruppen gruppiert werden, weshalb ich versuchte, die Unterklassen 'Bar',' Baz' usw. zu erstellen, um die verschiedenen Typen des gleichen Grundtyps 'Foo' zu behandeln. Sogar unter "Bar", "Baz", etc. gibt es mehr als eine davon in der Aufzeichnung und jede hat andere Standardeinstellungen. Deshalb dachte ich, dass null/Elvis ein guter Weg wäre, damit umzugehen ... Irgendwelche anderen Möglichkeiten? – sirksel

+0

Zu Ihrem zweiten Punkt über 'IllegalArgumentException', denke ich, dass das meine nächste beste Option ist. In diesen Fällen wird jedoch ein Fehler ** erwartet ** und wird oft vorkommen. Ich wollte auch keinen Standard hinter den Kulissen erzeugen ... deshalb wollte ich das angewendete '?: Default' an der Aufrufseite offen legen, aber dafür muss ein sekundärer Konstruktor' orNull' verwendet werden . 90% der Instanziierungen wird der primäre nullsichere Konstruktor, aber der begleitende/sekundäre validierende Konstruktor würde nur zur Verarbeitung externer Eingaben verwendet werden, wo ein Fehler wahrscheinlich ist. Offen für andere Gedanken ... – sirksel

+1

In Bezug auf andere Optionen: In diesem Fall würde ich die Validierung abstrakt machen, so dass die Unterklassen die Regeln zur Verfügung stellen müssen, die bei der Validierung während der Konstruktion verwendet werden können. – s1m0nw1

Verwandte Themen