2013-04-12 8 views
6

Mam bardzo powszechny wzorzec "dany Foo, zwracam Bar", na przykład, biorąc pod uwagę user_id, zwracam User.Konwencja nazw funkcji dla "przekonwertuj foo na słupek"

Czy istnieje konwencjonalny wzorzec nazewnictwa dla tego rodzaju funkcji? Po Joel on Software, ja osobiście użyłem dużo bar_from_foo(), ale rzadko widzę, jak inni to robią i szybko staje się gadatliwy, np.

widgets = user_widgets_from_user(user_from_param_map(params)) 

Czy istnieje konwencjonalny sposób do nazwy lub nazw (np User.from_map()) w którymś z popularnych języków tam? Szczególnie interesuje mnie Python, ale każdy język, który wymyślisz, byłby przydatny.

+3

Lubię User.from_user_id (id_użytkownika) – Patashu

Odpowiedz

3

myślę, że dużo zależy od kontekstu i wyborze znaczącej metafory. ActiveRecord na przykład używa metody klasy "find" do odnajdywania rekordów w bazie danych, bardziej sensownego pomysłu niż "input a user_id, output user". Na przykład:

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

W przypadku konwersji zwykle lubię pisać metody konwersji, aby ułatwić korzystanie z funkcji wyższego rzędu. Na przykład w ruby, konwersje są często wykonywane metodami to_* instancji, na przykład konwertować Foo do Bar warto byłoby mieć to_bar metodę dla wszystkich Foo, więc można napisać:

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

A potem konwertować kilka Foo, można po prostu:

bars = foos.map(&:to_bar) 

Ruby zmierza również mieć Foo.parse(str) do konwertowania ciąg do obiektu.


Dla javascript, lubię mieć metody klasy (który dostałem od standardowego ml), na przykład:

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

A potem można odwzorować na nim również (przy użyciu podkreślenia w tym przykładzie) :

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

konwencja standardowe ML struktury (klasa) metody. Typy Przykład Fn:

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

I chcesz go używać jak:

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

Jeśli chcesz przekonwertować coś na inny, na przykład na ciąg do liczby całkowitej, należy zdefiniować metodę w odbiorniku, a tym samym jej klasa jest jasna, więc nie powinieneś umieszczać klasy odbiornika jako części nazwa metody: String#to_i, a nie String#string_to_i. Jest to jedna z podstawowych idei programowania obiektowego (polimorfizm).

Jeśli odbiornik jest zbyt ogólne, aby przypisać taki sposób, na przykład jeśli user_id jest zwykłym ciąg, oraz określenie sposobu na String przekonwertować go do User nie wygląda dobrze, to należy zdefiniować konstruktora na klasa, której oczekujesz wartości zwracanej: User.new lub User.from_id.

15

chciałbym wykorzystać elastyczność nazewnictwa Clojure i nazwać go:

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

Dla mnie sprawia, że ​​całkiem jasne intencje i to dość krótki.

+4

Jako, że celem według OP jest "" biorąc pod uwagę Foo, zwróć pasek ", byłoby jeszcze lepiej, gdybyś to nazwał 'foo-> bar'' –

+0

Tks. Edytowano odpowiedź. – leonardoborges

+1

W Clojure użyłbym otwartej wysyłki (multimethods lub protokoły) i nazwałbym ją po prostu 'bar'. Spróbowałbym również uczynić to idempotentnym, aby dwukrotne wywoływanie go było bezowocne. Tak działa na przykład 'seq'. – cgrand

5

W języku Python i wielu innych językach OO powinien to być konstruktor na pasku, który przyjmuje jeden argument Foo jako jedyny argument. Ponieważ Python nie robi przeciążania metod (a próby emulacji są zwykle kruche), jeśli Bar.__init__ przyjmuje już inną sygnaturę, konwencja jest dokładnie twoja ostatnia. Co ważne, jest to zazwyczaj zdefiniowany jako klasa metody zamiast metody statyczne (z korzyścią dla podklasy):

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

Dlaczego umieszczenie typ parametru nazwa funkcji? Myślę, że byłoby bardziej przejrzyste coś

a_bar = bar_from(a_foo) 

wtedy można liczyć na dynamiczny wysyłki lub przeciążenia w wielu językach ... na przykład w Pythonie realizacja może próbować wywołać x.toBar() jeśli występuje lub może to sprawdzić na globalnym rejestr taki jak Bar_builders[type(x)](x); w Lisp można polegać na metodach; w C++ na przeciążeniach ...

+0

+1; Tak też działają rzeczy w R –

Powiązane problemy