2016-04-04 18 views
11

Zincirlemek istediğim birkaç CompletionStage yöntemim var. Sorun, birincisinin sonucunun, bir sonrakilerin gerçekleştirilip gerçekleştirilmeyeceğini belirleyeceğidir. Şu anda bunu başarmanın tek yolu, "özel" argümanları bir sonraki CompletionStage numarasına aktarıyormuş gibi görünmektedir, bu yüzden kodun tamamını işlemez.Sadece bir koşul sağlandığında birkaç Tamamlama İstasyonunu Zincirleme

public enum SomeResult { 
    RESULT_1, 
    RESULT_2, 
    RESULT_3 
} 

public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) { 

    return CompletableFuture.supplyAsync(() -> { 
     // loooooong operation 
     if (someCondition) 
      return validValue; 
     else 
      return null; 
    }).thenCompose(result -> { 
     if (result != null) 
      return someMethodThatReturnsACompletionStage(result); 
     else 
      return CompletableFuture.completedFuture(null); 
    }).thenApply(result -> { 
     if (result == null) 
      return ChainingResult.RESULT_1; 
     else if (result.someCondition()) 
      return ChainingResult.RESULT_2; 
     else 
      return ChainingResult.RESULT_3; 
    }); 
} 

bütün kodu (o false ise bütün kod yürütülmesi gereken değil o, o zaman sonuç, RESULT_1 olacaktır) bu yapı bana çirkin biraz görünüyor ilk someCondition bağlı olduğundan Örneğin:. 2. (thenCompose(...)) ve 3. (thenApply(...)) yöntemlerinin uygulanmasının gerekip gerekmediğine karar vermenin herhangi bir yolu var mı?

cevap

7

Böyle yapabilirsiniz:

public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) { 
    CompletableFuture<SomeResult> shortCut = new CompletableFuture<>(); 
    CompletableFuture<ResultOfFirstOp> withChain = new CompletableFuture<>(); 

    CompletableFuture.runAsync(() -> { 
     // loooooong operation 
     if (someCondition) 
      withChain.complete(validValue); 
     else 
      shortCut.complete(SomeResult.RESULT_1); 
    }); 
    return withChain 
     .thenCompose(result -> someMethodThatReturnsACompletionStage(result)) 
     .thenApply(result -> 
        result.someCondition()? SomeResult.RESULT_2: SomeResult.RESULT_3) 
     .applyToEither(shortCut, Function.identity()); 
} 

Yerine biri CompletableFuture biz alabilir farklı bir yürütme yolları temsil eden iki oluşturun. Loooooong işlemi, daha sonra çalıştırılabilir olarak sunulur ve bu CompletableFuture'dan birini bilinçli olarak tamamlar. Takip aşamaları, yerine getirilen koşulu temsil eden aşamaya zincirlenir, daha sonra her iki yürütme yolu da son applyToEither(shortCut, Function.identity()) adımında birleştirilir.

shortCut gelecek zaten nihai sonucun türü olan ve RESULT_1 ile tamamlanmış olacak, tüm operasyonun hemen tamamlandığını neden olacaktır null geçen yolun, sonucudur. İlk aşamada ve kısa kesim gerçek sonuç değeri arasındaki bağımlılık beğenmezseniz, böyle geri çekebilirsiniz:

public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) { 
    CompletableFuture<Object> shortCut = new CompletableFuture<>(); 
    CompletableFuture<ResultOfFirstOp> withChain = new CompletableFuture<>(); 

    CompletableFuture.runAsync(() -> { 
     // loooooong operation 
     if (someCondition) 
      withChain.complete(validValue); 
     else 
      shortCut.complete(null); 
    }); 
    return withChain 
     .thenCompose(result -> someMethodThatReturnsACompletionStage(result)) 
     .thenApply(result -> 
        result.someCondition()? SomeResult.RESULT_2: SomeResult.RESULT_3) 
     .applyToEither(shortCut.thenApply(x -> SomeResult.RESULT_1), Function.identity()); 
} 

üçüncü basamak örnek değildi ama tam olarak böyle gösterilir görünüyorsa söz konusu, kod yolu katılmadan adımla bunu birleştirebilir:

public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) { 
    CompletableFuture<ResultOfSecondOp> shortCut = new CompletableFuture<>(); 
    CompletableFuture<ResultOfFirstOp> withChain = new CompletableFuture<>(); 

    CompletableFuture.runAsync(() -> { 
     // loooooong operation 
     if (someCondition) 
      withChain.complete(validValue); 
     else 
      shortCut.complete(null); 
    }); 
    return withChain 
     .thenCompose(result -> someMethodThatReturnsACompletionStage(result)) 
     .applyToEither(shortCut, result -> result==null? SomeResult.RESULT_1: 
      result.someCondition()? SomeResult.RESULT_2: SomeResult.RESULT_3); 
} 

sonra yalnızca ikinci adımı, someMethodThatReturnsACompletionStage çağırmayı atlıyor ancak bu yine de, ara adımların uzun zinciri için durabiliriz, tüm olmadan atlanır nullcheck ile manuel bir atlama yapmak gerekiyor. tamlığı @Holger önerdiği çözüm inşaat büyük benim için biraz garip olsa da yeni bir cevap

ekliyorum uğruna

+0

Çalışır, teşekkürler! Aynı kalıbı takip ederek (birkaç CompletableFuture işlevi oluşturulduğunda ve applyToEither (...) 'yi kullanarak) onu çeşitli yollara genişletmek mümkün olabilir, değil mi? – Pelocho

+1

Evet, bunu birden fazla yola genişletebilirsiniz, ancak ortaya çıkan kodun bakımını yapmaya devam etmelisiniz. Belki de, bir dalın mantığını, birçok kez kullanabileceğiniz bir yardımcı program biçiminde kapsüllemeye yardımcı olur. – Holger

0

.

public enum SomeResult { 
    RESULT_1, 
    RESULT_2, 
    RESULT_3 
} 

public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) { 

    return CompletableFuture.supplyAsync(() -> { 
     // loooooong operation 
     if (someCondition) 
      return operateWithValidValue(value); 
     else 
      return CompletableFuture.completedValue(ChainingResult.RESULT_1); 
    }) 
     .thenCompose(future -> future); 

public CompletionStage<SomeResult> operateWithValidValue(... value) { 
    // more loooong operations... 
    if (someCondition) 
     return CompletableFuture.completedValue(SomeResult.RESULT_2); 
    else 
     return doFinalOperation(someOtherValue); 
} 

public CompletionStage<SomeResult> doFinalOperation(... value) { 
    // more loooong operations... 
    if (someCondition) 
     return CompletableFuture.completedValue(SomeResult.RESULT_2); 
    else 
     return CompletableFuture.completedValue(SomeResult.RESULT_3); 
} 

NOT: Ben kullanıyorum çözüm farklı yöntem çağrılarında farklı akışları ayrılması ve thenCompose ile zincirleme içerir Ben daha tam cevap uğruna söz dan algoritmayı değiştirdik

Tüm uzun işlemler içeriğinin içinde başka bir şekilde sarılabilir.

İlgili konular