2014-10-31 11 views
6

Chciałbym łańcuchów BiFunctions, podobnie jak w metodzie chainWanted w poniższym przykładzie kodu.Jak łańcuch BiFunctions?

BiFunction przyjmuje Funkcję jako parametr Andenna. czy można w jakiś sposób połączyć BiFunctions?

Kod tutaj nie kompiluje się z tego powodu i nie mogę rzucić BiFunction do funkcji.

import java.util.function.BiFunction; 
import java.util.function.Function; 

import org.openqa.selenium.remote.RemoteWebDriver; 

public class Wf { 

    BiFunction<RemoteWebDriver, WfParams, RemoteWebDriver> init = this::init; 
    BiFunction<RemoteWebDriver, WfParams, RemoteWebDriver> wait = this::wait; 

    BiFunction<RemoteWebDriver, WfParams, RemoteWebDriver> chainNow = init 
      .andThen(d -> { 
       System.out.println("--------------"); 
       return null; 
      }); 

    BiFunction<RemoteWebDriver, WfParams, RemoteWebDriver> chainWanted = init 
      .andThen((BiFunction) wait); 

    public RemoteWebDriver init(RemoteWebDriver d, WfParams params) { 
     System.out.println("init(d, params)"); 
     return d; 
    } 

    public RemoteWebDriver wait(RemoteWebDriver d, WfParams params) { 
     System.out.println("Wf.wait(d, params)"); 
     return d; 
    } 

    public static void main(String[] args) throws Exception { 
     new Wf().start(); 
    } 

    private void start() { 
     chainNow.apply(null, null); 
    } 
} 
+0

Nie widzę sposobu na rozpoczęcie bifunkcji łańcuchowych; wynik bifunkcyjny jest pojedynczym argumentem, jak zamierzasz go połączyć w inny? – fge

Odpowiedz

0

Skąd pochodzą WfParams do wywołania wait? Jeśli chcesz ponownie użyć tych samych WfParams dla wszystkich wywołań funkcji, po prostu ustaw WfParams jako zmienną członkowską klasy zamiast przekazywać ją do każdej funkcji.

class Wf { 
    private final WfParams params; 

    public Wf(WfParams params) { 
     this.params = params; 
    } 

    UnaryOperator<RemoteWebDriver> init = this::init; 
    UnaryOperator<RemoteWebDriver> wait = this::wait; 

    Function<RemoteWebDriver,RemoteWebDriver> chain = init.andThen(wait); 

    RemoteWebDriver init(RemoteWebDriver d) { 
     // can use WfParams here 
     return d; 
    } 

    RemoteWebDriver wait(RemoteWebDriver d) { 
     // can use WfParams here    
     return d; 
    } 

    private void start() { 
     chain.apply(null); 
    } 

    public static void main(String[] args) { 
     new Wf(new WfParams()).start(); 
    } 
} 

Czy jest jakiś szczególny powód, dla którego chcesz używać funkcji łączenia łańcuchów? Dlaczego nie po prostu zadzwonić pod numer init(...); wait(...); z start()?

3

Łańcuch jednego z nich Function do innego działa naturalnie, ponieważ zwracana wartość pierwszej funkcji jest przekazywana jako argument do następnej funkcji, a wartość zwracana przez funkcję jest przekazywana jako argument do następnej funkcji i tak dalej. To nie działa naturalnie z BiFunction, ponieważ pobiera dwa argumenty. Pierwszy argument byłby wartością zwracaną z poprzedniej funkcji, ale jaki byłby drugi argument? Wyjaśnia również, dlaczego BiFunction umożliwia połączenie z andThen do Function zamiast do innego BiFunction.

Sugeruje to jednak, że możliwe byłoby powiązanie jednego BiFunction z innym, gdyby istniał jakiś sposób dostarczenia wartości dla drugiego argumentu. Można to zrobić, tworząc funkcję pomocniczą, która przechowuje wartość dla drugiego argumentu w zmiennej lokalnej. Następnie można przekonwertować BiFunction na Function, przechwytując tę ​​zmienną lokalną ze środowiska i używając jej jako drugiego argumentu.

Oto, jak to będzie wyglądać.

BiFunction<RemoteWebDriver, WfParams, RemoteWebDriver> chainWanted = this::chainHelper; 

RemoteWebDriver chainHelper(RemoteWebDriver driver, WfParams params) { 
    return 
     init.andThen(rwd -> wait.apply(rwd, params)) 
      .apply(driver, params); 
} 

// ... 

chainWanted.apply(driver, params); 

Sposób chainHelper posiada params argument dla późniejszego przechwytywania. Nazywamy się init.andThen(), aby wykonać łańcuch. Ale wymaga to Function, natomiast wait to. Zamiast stosowania Referencyjna metoda this::wait używamy wyrażenia lambda

rwd -> wait.apply(rwd, params) 

który przechwytuje params ze środowiska leksykalnego. To daje wyrażenie lambda, które przyjmuje pojedynczy argument i zwraca pojedynczą wartość, więc jest to teraz Function, które owija wait, które jest BiFunction. Jest to przykład aplikacji z częściowym zastosowaniem lub z funkcją curry. Na koniec wywołujemy wynik BiFunction przy użyciu apply(), przekazując oryginalne argumenty.