W java.util.function
pakiecie Java 8 mamy:
- Funkcja : Bierze jeden argument, daje jeden wynik.
- Konsument : bierze jeden argument, nic nie produkuje.
- Dostawca : Nie bierze argumentu, daje jeden wynik.
- ... : Inne sprawy obsługujące operacje podstawowe, 2 argumenty itp.
Ale muszę sobie poradzić z przypadkiem „ nie bierze argumentu, nic nie produkuje ”.
W tym nie ma nic java.util.functionnal
.
Pytanie brzmi:
Jak nazywa się „ funkcja, która nie przyjmuje argumentów i niczego nie zwraca ”?
W Javie 8 jego definicją byłoby:
@FunctionalInterface
public interface InsertANameHere {
void execute();
}
Executor już istnieje i ma inny cel: „ Obiekt, który wykonuje przesłane zadania Runnable ”. Podpis nie pasuje ( execute(Runnable):void
) i nie jest nawet funkcjonalnym interfejsem .
Runnable istnieje, ale jest silnie powiązany z kontekstem wątków:
- Pakiet
java.lang
nie jestjava.util.function
. - Jawadoc stwierdza: „ Interfejs Runnable powinien być implementowany przez każdą klasę, której instancje mają być wykonywane przez wątek ”.
- Nazwa „Runnable” sugeruje trochę działającego kodu w wątku.
java
functional-programming
java8
superbob
źródło
źródło
Runnable
jest w tym momencie nieaktualny, ponieważ Runnable jest również używany przez inne klasy niżThread
(Executor
na przykład).Runnable
S może być tylko.run()
przezThread
sekundę. W rzeczywistości są one bardzo często używane dokładnie do celu opisanego w pytaniujava.util.function
pakiecie.Odpowiedzi:
Wybór Javy, aby zrobić to w ten sposób z osobną nazwą dla każdego ariana, był głupi. Nie jest to warte naśladowania. Jeśli jednak musisz zachować spójność lub piszesz bardzo ogólny kod biblioteki, sugestie Konrada są dobre. Mogę rzucić
Procedure
w pierścień.Użycie pseudo-funkcjonalnego paradygmatu nie oznacza, że normalne zasady nazewnictwa powinny wyjść z okna. Interfejsy należy prawie zawsze nazywać po tym, co robią , a nie po ogólnym pomyśle syntaktycznym. Jeśli funkcje zostaną umieszczone w stosie cofania, należy je nazwać
UndoFunction
. Jeśli są wywoływane ze zdarzeń GUI, należy je nazwaćGUIEventHandler
. Przyjaciele nie pozwalają przyjaciołom utrwalać złych konwencji nazewnictwa.źródło
Procedure
też jest w porządku. W kontekście opracowuję bibliotekę ogólną, która musi obsługiwać tego rodzaju „strukturę”.Procedure
od moich pascal dni. AProcedure
ma skutki uboczne, aFunction
nie. Ponieważ nie zwracasz wartości, jedyne, co może zrobić, to mieć efekt uboczny.ProcedureRIR<T1,T2>
zvoid proc(T1, int, T2)
, a także dla innych typów - prawdopodobnie tworząc większość z nich na żądanie zamiast próbować dopchać w każdej możliwej kombinacji typów.If the functions are placed into an undo stack, they should be named UndoFunction.
Istnieje jednak różnica między nazwaniem funkcji a nadaniem jej innego typu. W funkcjonalnym stylu nie spowodowałobyUndoFuncton
typ bo teraz nie można przekazać go doflip
,curry
,compose
,filter
,map
, itp w moim przekonaniu , że jest prawdziwym powodem decyzji Java dać funkcje z różnych arities różne nazwy jest głupie. Oczywiście, jeśli zamierzasz stosować efekty uboczne, nazwij to jakkolwiek; już wyrzuciłeś kompozycję przez okno i prawdopodobnie też nie używasz funkcji.W świecie Java nazywa się to
Runnable
. W świecie C # nazywa się toAction
.Ale istnieje lepsza nazwa, która ładnie pasuje do szerszego widoku rzeczy.
Szerszy widok rzeczy pojawia się później, gdy zdecydujesz, że oprócz twojego pozbawionego parametrów pustego interfejsu funkcjonalnego potrzebujesz także podobnych interfejsów funkcjonalnych, które akceptują jeden, dwa lub więcej argumentów lub zwracają wartość. Kiedy tak się stanie, będziesz chciał, aby nazwy wszystkich tych bytów były izomorficzne i korespondowały ze sobą.
Tak więc w Javie mam własny zestaw interfejsów funkcjonalnych, które nazywam
Procedure
s, zdefiniowane w następujący sposób:... (Dostajesz obraz.)
Mam również podobny zestaw interfejsów o nazwie
Function
s, zdefiniowany w podobny sposób, przy czym pierwszym parametrem ogólnym jest typ zwracany:Chodzi mi o to, że
Procedure
jest to bardzo dobre imię, ponieważ ładnie pasuje do szerszego widoku rzeczy. Jeśli później zdecydujesz się na podobne interfejsy funkcjonalne z metodami, które akceptują argumenty lub zwracają wartość, natkniesz się na to.UWAGA: Zasadniczo zgadzam się z twierdzeniem Karla Bielefeldta, że „normalne zasady nazewnictwa powinny [nie] wychodzić z okna” i że „interfejsy należy prawie zawsze nazywać po tym, co robią, a nie po ogólnym pomyśle syntaktycznym”. Pamiętaj jednak, że nawet on pozwala na „prawie zawsze”. Czasami potrzebne są (zasadniczo anonimowe) procedury i funkcje, i właśnie o to prosi OP, i na to odpowiadam.
Poprawka 2017-11-10:
Możesz zapytać, dlaczego
Function1<R,T1>
zamiastFunction1<T1,R>
? Może pójść w obie strony, ale preferuję zwracanie wartości po lewej stronie, ponieważ lubię stosować konwencję nazewnictwa „konwersja z” (miejsce docelowe z źródła) w przeciwieństwie do „konwersji do” -destination) konwencja. (Co jest bardziej wypadkiem niż konwencją, w rzeczywistości w tym sensie, że najprawdopodobniej nikt nigdy nie zastanawiał się nad tym, ponieważ gdyby w ogóle się nad tym zastanowili, doszliby do konwencji o nawróceniu. )Przeczytałem o tym w Joel Spolksy - Sprawianie, że zły kod wygląda źle , jest to bardzo długi artykuł, który polecam przeczytać w całości, ale jeśli chcesz przejść bezpośrednio do omawianej sprawy, wyszukaj „TypeFromType”, ale aby dać TL; DR, pomysł jest o
myint = intFromStr( mystr )
wiele lepszy niżmyint = strToInt( mystr )
, ponieważ w pierwszym przypadku nazwy typów są zbliżone do powiązanych wartości, dzięki czemu można łatwo zobaczyć, że „int” pasuje do „int” i „str” pasuje do „str”.Tak więc, przez rozszerzenie, mam tendencję do porządkowania rzeczy w taki sposób, w jaki będą wyglądały w kodzie.
źródło
Function1<T1, R>
jestDlaczego nie
Command
? Biorąc pod uwagę, że nie wymaga danych i nie zwraca żadnych danych, ale zakładając, że wywołanie go powoduje jakiś efekt (w przeciwnym razie byłoby to raczej bezcelowe), wyobrażam sobie, że jest to z grubsza jedyna rzecz, jaką może zrobić - uruchomić akcję, sprawić, by coś się stało.Mówiąc o tym, istnieje również ogólny
Action
delegat w .NET. W przeciwieństwie do JavyConsumer
może zająć od 0 do 16 argumentów; innymi słowy, najprostsza wersja tego nie wymaga - patrz MSDN .A ponieważ nazwa nie sugeruje, że ma się co „konsumować”, wydaje się, że to dobry wybór.
źródło
Command
jest dobry. Można go pomylić ze schematem poleceń, ale może to być rozwiązanie.Action
więcej niżCommand
. Polecenie brzmi bardziej jak coś, co jest odbierane i oceniane, podczas gdy akcja jest wykonywana dla jej skutków ubocznych.execute()
metodę. 0_o '