2016-01-12 7 views
6

Kotlin erlaubt, eine Funktion wie eine existierende Klasse zu benennen, z. HashSet mit initializer Funktion könnte wie folgt implementiert werden:Sollten wir es vermeiden, eine Funktion in Kotlin gleich einer vorhandenen Klasse zu benennen? Warum?

fun <T> HashSet(n : Int, fn: (Int) -> T) = HashSet<T>(n).apply { 
    repeat(n) { 
     add(fn(it)) 
    } 
} 

Wenn es verwendet wird, ist es wie ein normales HashSet Konstruktor aussieht:

var real = HashSet<String>() 
var fake = HashSet(5) { "Element $it" } 

dies vermieden oder gefördert werden soll und warum?

Antwort

13

UPD

In den aktualisierten Codierung Konventionen, es gibt eine section on this topic:

Werksfunktionen

Wenn Sie eine Fabrik-Funktion für eine Klasse deklarieren, vermeiden ihm das gleiche geben Name als die Klasse selbst. Verwenden Sie vorzugsweise einen eindeutigen Namen, um deutlich zu machen, warum das Verhalten der Factory-Funktion besonders ist. Nur wenn es wirklich keine spezielle Semantik gibt, können Sie den gleichen Namen wie die Klasse verwenden.

Beispiel:

class Point(val x: Double, val y: Double) { 
    companion object { 
     fun fromPolar(angle: Double, radius: Double) = Point(...) 
    } 
} 

Die Motivation I unten beschrieben wird, scheint aber noch halten.


Wie gesagt in der Dokumentation über die naming style:

Im Zweifelsfall standardmäßig auf die Java-Konventionen Coding wie:

  • Methoden und Eigenschaften mit Kleinbuchstaben beginnen

Ein starker Grund t o Vermeiden Sie eine Funktion derselben zu einer Klasse zu benennen ist, dass es vielleicht ein Entwickler verwirren, die sie später verwenden wird, weil, im Gegensatz zu ihren Erwartungen:

  • die Funktion nicht für Super Konstruktoraufruf verfügbar sein (wenn die Klasse ist open)
  • es nicht als Konstruktor durch Reflexion
  • sichtbar ist, wird es nicht als ein Konstruktor in Java-Code verwendbar sein wird (new HashSet(n, it -> "Element " + it) ist ein Fehler)
  • , wenn Sie später die Implementierung ändern möchten, und eine Unterklasseninstanz zurückgeben, wird es noch verwirrender, dass wil l Konstrukt kein HashSet aber zum Beispiel ein LinkedHashSet

Es ist besser, es explizit zu zeigen, dass es eine Fabrik-Funktion, kein Konstruktor, diese Verwirrung zu vermeiden.

Die Benennung einer Funktion, die einer Klasse entspricht, wird in der Regel auch in stdlib vermieden.Bei SomeClass ist in stdlib ein bevorzugter Benennungsstil für Factory-Funktionen someClassOf, someClassBy oder was auch immer erklärt die Semantik der Funktion am besten. Die Beispiele:

  • generateSequence { ... } und sequenceOf(...)
  • lazy { ... } und lazyOf(...)
  • compareBy { ... }
  • listOf(...), setOf(...), mapOf(...)

So sollte man auf jeden Fall haben guten Grund eine Funktion zu haben, eine nachahmen Konstrukteur.

Stattdessen kann der Name einer Funktion einem Benutzer mehr (sogar alles) über seine Verwendung erzählen.

+1

wirklich? Also, sekundäre Konstruktoren sind besser als Factory-Funktionen? Ich denke, wir brauchen eine offizielle Meinung (in der Dokumentation) – voddan

+1

@Voddan, die Frage und die Antwort sind nicht über sekundäre Konstruktoren, sie sind über eine Funktion haben, einen Konstruktor nachzuahmen. Was ist mit sekundären Konstruktoren, sie sind nutzlos, wenn eine Funktion eine Unterklasseninstanz mit einer anderen Implementierung zurückgeben soll. Sonst scheinen sie besser zu passen als Factory-Funktionen (Reflection, Super Ctor Call, Java Interop). – hotkey

+0

Nun, der einzige Vorschlag für Funktionen, die wie Klassen benannt werden, besteht darin, diese Klassen zu berücksichtigen, ohne den Klassencode zu überfluten. Die Alternative sind sekundäre Konstruktoren, und dies ist in Ihrer Antwort enthalten. – voddan

-2

Ich stimme mit + Hotkey. Es ist wahrscheinlich am besten, in diesem Fall Verwirrung zu vermeiden.

Wenn es nur intern verwendet wird und alle anderen Entwickler (falls vorhanden) damit einverstanden sind, würde ich sagen, dass ich dafür gehen muss. Python erkennt diese Idee an und ich liebe sie. Verdammt, sie gehen in beide Richtungen, sind auch okay, wenn du eine Klasse im Funktionsfall benennst, wenn es sich eher so anfühlt, als würde es sich wie eine Funktion verhalten. Aber Python muss sich nicht mit Java-Interop beschäftigen, also tun Sie es definitiv nicht für öffentlichen Code.

+2

Ich glaube nicht, dass wir Ideale anderer Sprachen als Antworten für "was ist das Beste in Kotlin" ziehen sollten. Und interner Code ändert nichts an der Tatsache, dass er branchenüblichen Best Practices folgen sollte, es sei denn, es gibt einen Grund genug, sich davon zu unterscheiden. –

+0

+ Jayson Minard Zunächst möchte ich darauf hinweisen, dass ich größtenteils zustimme. Zweitens denke ich, dass Namenskonventionen, die sich auf die Kapitalisierung beziehen, nicht wirklich als "Best Practice" gelten. Zum Beispiel sind C# und Java fast die gleiche Sprache, haben jedoch unterschiedliche Kapitalisierungskonventionen. Der Grund für diese Konventionen ist rein konsistenzbezogen, um die Lesbarkeit innerhalb einer bestimmten Sprachgemeinschaft zu gewährleisten. Also bleibe ich bei dem, was ich gesagt habe.Wenn jeder, der diesen Code liest, damit einverstanden ist, dann ist nichts falsch daran. Dies ist das Gleiche wie jede andere Konvention, die von einem Stylesheet eines Unternehmens vorgeschrieben wird. –

+0

Dies ist ein bisschen mehr als über Großschreibung. –

Verwandte Themen