2016-01-12 9 views
6

Kotlin consente di denominare una funzione come una classe esistente, ad es. HashSet con la funzione di inizializzazione potrebbero essere attuate in questo modo:Dovremmo evitare di nominare una funzione come una classe esistente in Kotlin? Perché?

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

Quando viene usato, si presenta come un normale HashSet costruttore:

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

questo dovrebbe essere evitato o incoraggiati e perché?

risposta

13

UPD

Nelle convenzioni di codifica aggiornati, c'è un section on this topic:

funzioni di fabbrica

Se si dichiara una funzione di fabbrica per una classe, evitare di dare lo stesso nome come la classe stessa. Preferisci usare un nome distinto per chiarire perché il comportamento della funzione di fabbrica è speciale. Solo se non c'è davvero una semantica speciale, puoi usare lo stesso nome della classe.

Esempio:

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

La motivazione che ho descritto qui di seguito, però, sembra tenere ancora.


Come detto nella documentazione sulla naming style:

In caso di difetto di dubbio al Java convenzioni di codifica, quali:

  • metodi e le proprietà iniziano con minuscole

Una ragione forte t o evitare di nominare una funzione stessa a una classe è che si potrebbe confondere uno sviluppatore che lo userà più tardi, perché, contrariamente alle loro aspettative:

  • la funzione non sarà disponibile per la chiamata Super costruttore (se la classe è open)
  • non sarà visibile come un costruttore attraverso la riflessione
  • non sarà utilizzabile come costruttore nel codice Java (new HashSet(n, it -> "Element " + it) è un errore)
  • se si desidera cambiare l'implementazione più tardi e restituire invece un'istanza di sottoclasse, sarà ancora più confuso il fatto che HashSet(n) { "Element $it" } wil l costrutto non un HashSet ma, per esempio, un LinkedHashSet

È meglio mostrare esplicitamente che è una funzione di fabbrica, non un costruttore, per evitare questa confusione.

Anche la denominazione di una funzione identica a una classe viene generalmente evitata anche in stdlib.Dato SomeClass, in stdlib uno stile di denominazione preferito per le funzioni di fabbrica è someClassOf, someClassBy o qualsiasi altra cosa spieghi la semantica della funzione migliore. Gli esempi:

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

Quindi, si dovrebbe sicuramente forte motivo per avere una funzione di imitare un costruttore.

Al contrario, il nome di una funzione potrebbe indicare all'utente (anche a tutto) il suo utilizzo.

+1

davvero? Quindi ora i costruttori secondari sono migliori delle funzioni di fabbrica? Penso che abbiamo bisogno di un parere ufficiale (nei documenti) – voddan

+1

@voddan, la domanda e la risposta non riguardano i costruttori secondari, si tratta di avere una funzione che imita un costruttore. Per quanto riguarda i costruttori secondari, essi non sono utili quando una funzione deve restituire un'istanza di sottoclasse con un'implementazione diversa. Altrimenti, sembrano adattarsi meglio delle funzioni di fabbrica (riflessione, chiamata super ctor, interopzione Java). – hotkey

+0

beh, l'unica proposta di funzioni denominate come classi è il factoring di quelle classi senza inondare il codice di classe. L'alternativa è costruttori secondari, ed è una specie di implicita nella tua risposta. – voddan

-2

Sono d'accordo con + tasto di scelta rapida. Probabilmente è meglio evitare confusione in questo caso.

Se è usato solo internamente e tutti gli altri sviluppatori (se ce ne sono) sono a posto, tuttavia, direi di provarlo. Python riconosce questa idea e la adoro. Diamine, vanno in entrambe le direzioni, va bene anche con il nominare una classe in caso di funzione, se sembra più come se agisse come una funzione. Ma Python non ha a che fare con l'interoperabilità Java, quindi sicuramente non farlo per codice pubblico.

+2

Non penso che dovremmo usare gli ideali di altre lingue come risposte per "cosa è meglio in Kotlin". E il codice interno non cambia il fatto che dovrebbe seguire le migliori pratiche in tutto il settore a meno che non ci sia una ragione sufficiente per differire. –

+0

+ Jayson Minard In primo luogo, voglio sottolineare che sono per lo più d'accordo. In secondo luogo, penso che le convenzioni di denominazione, attinenti alla capitalizzazione, non contino davvero come una "migliore pratica". Ad esempio, C# e Java sono quasi la stessa lingua ma hanno diverse convenzioni di maiuscole. La ragione di queste convenzioni è puramente di coerenza per motivi di leggibilità all'interno di una determinata comunità linguistica. Quindi, rimango fedele a ciò che ho detto.Se tutti quelli che leggono quel codice vanno bene, allora non c'è niente di sbagliato in questo. Questo è lo stesso di qualsiasi altra convenzione richiesta da un foglio di stile aziendale. –

+0

Questo è un po 'più di capitalizzazione. –

Problemi correlati