2013-04-12 8 views
6

Ho un modello molto comune di "dato un Foo, restituire un Bar", per esempio, dato un user_id, restituire un User.convenzione Nome della funzione per "convertire i foo a bar"

Esiste uno schema di denominazione convenzionale per questo tipo di funzioni? Seguendo Joel on Software, ho utilizzato personalmente molto bar_from_foo(), ma raramente vedo altre persone farlo e diventa rapidamente prolisso, ad es.

widgets = user_widgets_from_user(user_from_param_map(params)) 

Esiste un modo convenzionale per nome, o dello spazio dei nomi (per esempio User.from_map()) in una qualsiasi delle lingue popolari là fuori? Sono particolarmente interessato a Python, ma qualsiasi linguaggio tu possa pensare potrebbe essere utile.

+3

Mi piace User.from_user_id (user_id) – Patashu

risposta

3

Penso che dipende molto dal contesto e scegliendo una metafora significativa. ActiveRecord ad esempio usa il metodo di classe "find" per trovare i record nel database, un'idea più significativa di "input a user_id, output a user". Ad esempio:

User.find(user_id) 
User.find_by_email(user_email) 

per conversioni, di solito piace scrivere i metodi di conversione per rendere più facile da utilizzare in funzioni di ordine superiore. Per esempio in Ruby, le conversioni sono spesso fatto con i metodi to_* istanza, ad esempio, per convertire un Foo ad un Bar avrebbe senso avere un metodo to_bar per tutti i Foos, quindi si potrebbe scrivere:

foo = Foo.new(...) # make a new Foo 
bar = foo.to_bar  # convert it to a Bar 

E poi per convertire un gruppo di Foos, si potrebbe semplicemente:

bars = foos.map(&:to_bar) 

rubino tende anche ad avere Foo.parse(str) per convertire una stringa per l'oggetto.


per Javascript, mi piace avere metodi di classe (che ho ricevuto da ml di serie), per esempio:

Foo.toBar = function(foo) { 
    return new Bar(...); 
}; 

e poi si può mappare su di esso così (usando sottolineare in questo esempio) :

var bars = _.map(foos, Foo.toBar); 

la convenzione standard ML è la struttura metodi (classe). Esempio tipi FN:

Foo.toBar : foo -> bar 
Foo.fromBar : bar -> foo 

E tu saresti utilizzarlo come:

val bar = Foo.toBar foo; 
val bars = map Foo.toBar foos; 
5

Se si desidera convertire qualcosa in un altro, ad esempio una stringa in un numero intero, il metodo deve essere definito sul ricevitore e quindi la sua classe è chiara, quindi non si deve mettere la classe del ricevitore come parte del nome metodo: String#to_i, non String#string_to_i. Questo in una delle idee principali della programmazione orientata agli oggetti (polimorfismo).

Se il ricevitore è troppo generale per assegnare tale metodo, ad esempio se user_id è un semplice stringa e la definizione di un metodo su String per convertirlo in un User non guardare a destra, allora si dovrebbe definire un metodo di costruzione su la classe che prevede che il valore restituito sia: User.new o User.from_id.

15

Vorrei approfittare di flessibilità denominazione di Clojure e chiamarlo:

(defn foo->bar [] ...) 

Per me che rende l'intento chiaro ed è piuttosto breve.

+4

Poiché lo scopo secondo l'OP è "dato un Foo, restituisci una barra", sarebbe ancora più chiaro se lo chiamassi 'foo-> bar' –

+0

Tks. Modificato la risposta. – leonardoborges

+1

In Clojure vorrei sfruttare il dispatch aperto (multimetodi o protocolli) e nominarlo semplicemente "bar". Cercherò anche di renderlo idempotente, così che chiamarlo due volte non ha senso. Ecco come funziona 'seq' per esempio. – cgrand

5

In Python e in vari altri linguaggi OO, questo dovrebbe essere un costruttore su Bar che accetta un singolo Foo come unico argomento. Poiché Python non esegue il overloading dei metodi (e i tentativi di emulazione sono solitamente fragili), se Bar.__init__ accetta già una firma diversa, la convenzione è esattamente l'ultima. È importante sottolineare che questo è di solito definito come un metodo classe piuttosto che un metodo statico (a beneficio delle sottoclassi):

class Bar: 
     @classmethod 
     def from_foo(cls, f): 
      '''Create a new Bar from the given Foo''' 
      ret = cls() 
      # ... 
1

Perché ponendo il tipo del parametro il nome della funzione? Penso che sarebbe più chiaro qualcosa come

a_bar = bar_from(a_foo) 

allora si può fare affidamento su spedizione dinamica o sovraccarico in molte lingue ... per esempio in Python l'attuazione potrebbe provare a chiamare x.toBar() se presente o potrebbe verificare la presenza di un globale registro come Bar_builders[type(x)](x); in Lisp puoi contare su metodi; in C++ su sovraccarichi ...

+0

+1; Questo è anche il modo in cui le cose funzionano in R –

Problemi correlati