2016-04-11 11 views
1

Java 8ではコンシューマの条件付き合成が可能ですか?基本的に私はコンシューマーに似た独自のラムダインターフェイスを作成しようとしていますが、これはあるタイプのオブジェクトでのみ動作します。 (私たちは、この例の目的のための2つを言うでしょう)、のはそれを呼び出すStatefulをしてみましょう、それは複数の状態が含まれていますJava 8ステートフルコンシューマ

public class Stateful { 
    private int status1; 
    private int status2; 
} 

私たちは、ステートフルと上の操作を行う我々のコード内の領域の多くを持って、ステータスが変更された場合は、別の操作を行います。よりコンパクトでエレガントな方法でこれを処理するために合成を使用できるかどうか、私は疑問を抱いていました。

私はこのようなものがよく見えると思う
SimpleEntry<Integer, Integer> oldStates = new SimpleEntry(stateful.getStatus1(), stateful.getStatus2()); 

applyLogicOnStateful(stateful); //do some operation that may change state values 
if(isStatusChanged(oldStates, stateful) { //compare oldStates integers to status integers 
    doSomethingElse(stateful); 
} 

:今、私たちのようなものだろう

statefulConsumer 
.accept((stateful)->applyLogicOnStateful(stateful)) 
.ifStatusChanged((stateful)->doSomethingElse(stateful)); 

を私たちからの状態の変化を追跡することができるかどうかはわかりません最初の消費者の前に。たぶん、入力として2人の消費者を必要とするラムダを作成する必要がありますか?

サードパーティの図書館の助けを借りずにこれを行うことは間違いありませんが、役立つ場合はここで宣伝してください。

+1

これを行うための「コンパクトでエレガントな」方法は、例えば、完全に正常な、読み込み可能な 'if'ステートメントを使用します。 –

+0

私は敬意を表して同意しません。変数を状態に保存して、ロジックを実行してから、比較を大量に行い、間違いなくDRYではありません。私は、しかし、状態が変更された場合は、ブール値を返す変更された消費者を持つことができると思います。 – IcedDante

+2

私はこれを行う唯一の方法は、あなたのステータスが変更された場合、またはあなたのすべての操作を呼び出す前に期待値を使って述語を作成する場合、applyLogicOnStatefulがbooleanを返すかどうかです。 ) –

答えて

0

これは、元の状態を抽出し、変更を行い、結果を比較し、変更されたオブジェクトを条件付きで操作するConsumer<Stateful>を返す関数です。

Consumer<Stateful> ifChanged = getStatefulConsumer(s -> new SimpleEntry<> (s.status1, s.status2), 
    s -> changeSomething(s), Objects::equals, s->doSomething(s)); 

あなたは異なるステートフルなタイプが異なる抽出されたステータスタイプを持つことができるように抽出された状態をgenerify、あるいはステートフルを使用することができます::状態をコピーするクローン:あなたはこのようにそれを使用する場合があります

public static Consumer<Stateful> getStatefulConsumer(
     Function<Stateful,SimpleEntry<Integer,Integer>> getStatus,     // extract status from Stateful 
     Consumer<Stateful> applyLogic,            // apply business logic 
     BiPredicate<SimpleEntry<Integer,Integer>,SimpleEntry<Integer,Integer>> compareState, // test statuses for change 
     Consumer<Stateful> onChange)            // doSomethingElse 
{ 
    return stateful -> { 
     SimpleEntry<Integer,Integer> oldStatus = getStatus.apply(stateful); 
     applyLogic.accept(stateful); 
     if(!compareState.test(oldStatus, getStatus.apply(stateful))){ 
      onChange.accept(stateful); 
     } 
    }; 
} 

+0

ありがとうHank-私は実際に、その状態を判断するために古い状態情報が必要なので、 'statusChanged'メソッドの概要を間違えました。私は混乱の謝罪とそれを反映するために私のオリジナルの質問を編集します。 – IcedDante

+0

私はあなたのフィードバックを考慮に入れて私の答えを編集しました。どう考えているか教えてください。 –

+1

'Consumer 'として返すことの利点の1つは、 'Stream.forEach()'、 'Collection.forEach()'、 'Optional.ifPresent'、' CompletableFuture.thenAccept() 'のような様々なAPIで使うことができるということです。 ) 'など。 –

0

私は今で働いているソリューションは、入力としてステートフルインスタンスと2つのコンシューマを取るラムダ・インターフェースを作成することです:

public interface StatefulConsumer { 
    void accept(Stateful stateful, Consumer<Stateful> consumer, Consumer<Stateful> ifStateChangedConsumer); 
} 

と実装:

可能性があり
final StatefulConsumer IfStateChanges = new StatefulConsumer() { 
    @Override 
    public void accept(Stateful stateful, Consumer<Stateful> consumer, Consumer<Stateful> ifStateChangedConsumer) { 
     SimpleEntry<Integer, Integer> oldStates = new SimpleEntry(stateful.getStatus1(), stateful.getStatus2()); 

     consumer.accept(stateful); //do some operation that may change state values 
     if(isStatusChanged(oldStates, stateful) { //compare oldStates integers to status integers 
      ifStateChangedConsumer.accept(stateful); 
     } 
    } 
}; 

IfStateChanges.accept(ステートフル、 (ステートフル)) - > applyLogicOnStateful(ステートフル)、 (ステートフル) - > doSomethingElse(ステートフル))

これは、ステートフルとコンシューマを入力として受け取り、if文で使用するブール値を返す述語または関数として実装することもできます

+0

私たちは同様のタックに終わったようです。素晴らしい心。 :-) –