2017-05-18 9 views
2
私は(/ Javaの7アッカ2.4.8から)アッカ2.5.1およびJava 8に、既存のコードベースを移行しています

のすべてのケースから、共通のコードを抽出しないと私は持っているコードのよう:は、どのように私はアッカ2.5 ReceiveBuilder

ReceiveBuilderを使用しアッカ2.5.1では
public void onReceive(Object message) throws Exception { 
    /* Start type specific processing */ 
    if (message instanceof Foo) { 
    processFoo(); 
    } else if (message instanceof Bar) { 
    processBar(); 
    } else if (message instanceof Bash) { 
    processBash(); 
    } else if (message instanceof Otherthing) { 
    processOtherThing(); 
    } 
    /* End type specific processing */ 

    /* Start common processing */ 
    doSomethingForAllMessages(); 
    /* End common processing */ 
} 

これは次のようになります。これは、共通の処理doSomethingForAllMessages()を行わないことを除いて

public Receive createReceive() { 
    return receiveBuilder() 
     .match(Foo.class, this::processFoo) 
     .match(Bar.class, this::processBar) 
     .match(Bash.class, this::processBash) 
     .match(OtherThing.class, this::processOtherThing) 
     .build(); 
} 

...。この共通処理を各match()節に追加するのではなく、慣用的なJava 8/Akka 2.5.1の方法がありますか?

更新

私のようなものを探しています:あなたが実際にReceiveないReceiveBuilderで返す何

public Receive createReceive() { 
    return receiveBuilder() 
     .match(Foo.class, this::processFoo) 
     .match(Bar.class, this::processBar) 
     .match(Bash.class, this::processBash) 
     .match(OtherThing.class, this::processOtherThing) 
     .andThen(this::doSomethingForAllMessages) 
     .build(); 
} 
+0

[matchAny(http://doc.akka.io/japi/akka/2.5/akka/japi/pf/ReceiveBuilder.html#matchAny-akka.japi.pf.FI.UnitApply-)を満たしていますあなたの要件。 –

+0

私はテストして見ていきますが、それはドキュメントに表示されているもの、たとえばhttp://doc.akka.io/docs/akka/current/java/actors.htmlとは一致しません。私は各メッセージクラスで異なる動作が必要ですが、すべてのメッセージについても共通の処理が必要です。 –

答えて

1

Receiveの最終的なであるので、scala.PartialFunctionを構成できるすべてのメッセージを処理したい場合は、例えば:

Receive createReceive() { 
    return thenAccept(
      receiveBuilder() 
        .match(Foo.class, this::processFoo) 
        .match(Bar.class, this::processBar) 
        .match(Bash.class, this::processBash) 
        .match(OtherThing.class, this::processOtherThing) 
        .build(), 
      this::doSomethingForAllMessages 
    ); 
} 

<T> Receive thenAccept(Receive origin, FI.UnitApply<T> action) { 
    return new Receive(thenAccept(origin.onMessage(), action)); 
} 

<A, B> PartialFunction<A, B> thenAccept(PartialFunction<A, B> fn, 
            FI.UnitApply<A> action) { 
    return Function.unlift(thenAccept(fn.lift(), action)); 
} 

<A, B> Function1<A, Option<B>> thenAccept(Function1<A, Option<B>> fn, 
             FI.UnitApply<A> action) { 
    return it -> { 
     Option<B> value = fn.apply(it); 
     action.apply(it); 
     return value; 
    }; 
} 

場合は、あなたのニーズを達成するためにscala APIを操作する必要はありません。なんらかの理由で、Function1は、以前のバージョンのscalaの@FunctionalInterfaceではありません。 ReceiveBuilderを作成することができます。例えば:

public Receive createReceive() { 
    return thenAccept(
      receiveBuilder() 
        .match(Foo.class, this::processFoo) 
        .match(Bar.class, this::processBar) 
        .match(Bash.class, this::processBash) 
        .match(OtherThing.class, this::processOtherThing), 
      this::doSomethingForAllMessages 
    ).build(); 
} 

ReceiveBuilder thenAccept(ReceiveBuilder origin, FI.UnitApply<Object> action) { 
    return ReceiveBuilder.create().matchAny(allOf(
      origin.build().onMessage()::apply, 
      action 
    )); 
} 

FI.UnitApply<Object> allOf(FI.UnitApply<Object>... actions) { 
    return it -> { 
     for (FI.UnitApply<Object> action : actions) { 
      action.apply(it); 
     } 
    }; 
} 

ORあなたはReceiveBuilderを組み合わせることにより、セマンティクスの一貫性を保つことができます。 ReceiveBuilderに属しているよう

public Receive createReceive() { 
    return both(
      receiveBuilder() 
        .match(Foo.class, this::processFoo) 
        .match(Bar.class, this::processBar) 
        .match(Bash.class, this::processBash) 
        .match(OtherThing.class, this::processOtherThing), 
      receiveBuilder().matchAny(this::doSomethingForAllMessages) 
    ).build(); 
} 

ReceiveBuilder both(ReceiveBuilder left, ReceiveBuilder right) { 
    return ReceiveBuilder.create().matchAny(it -> Stream.of(left,right) 
      .map(ReceiveBuilder::build) 
      .map(Receive::onMessage) 
      .forEach(action->action.apply(it))); 
} 

ORthenAccept挙動が見えますが、あなたはそれを達成するためのより多くの努力を取る必要がある、と継承を使用しているとき、それはカプセル化を破ります。

public Receive createReceive() { 
    return AcceptableReceiveBuilder.create() 
        .match(Foo.class, this::processFoo) 
        .match(Bar.class, this::processBar) 
        .match(Bash.class, this::processBash) 
        .match(OtherThing.class, this::processOtherThing) 
        .thenAccept(this::doSomethingForAllMessages) 
        .build(); 
} 



class AcceptableReceiveBuilder extends ReceiveBuilder { 
    private List<FI.UnitApply<Object>> afterActions = new ArrayList<>(); 

    public static AcceptableReceiveBuilder create() { 
     return new AcceptableReceiveBuilder(); 
    } 

    @Override 
    public 
    <P> AcceptableReceiveBuilder match(Class<P> type, FI.UnitApply<P> action) { 
     return this.matchUnchecked(type, action); 
    } 

    @Override 
    public 
    AcceptableReceiveBuilder matchUnchecked(Class<?> type, 
              FI.UnitApply<?> action) { 
     return (AcceptableReceiveBuilder) super.matchUnchecked(type 
       , compose(action)); 
    } 

    @Override 
    public 
    <P> AcceptableReceiveBuilder match(Class<P> type, 
             FI.TypedPredicate<P> condition, 
             FI.UnitApply<P> action) { 
     return this.matchUnchecked(type, condition, action); 
    } 

    @Override 
    public 
    <P> AcceptableReceiveBuilder matchUnchecked(Class<?> type, 
               FI.TypedPredicate<?> condition, 
               FI.UnitApply<P> action) { 
     return (AcceptableReceiveBuilder) super.matchUnchecked(type, condition 
       , compose(action)); 
    } 

    @Override 
    public 
    <P> AcceptableReceiveBuilder matchEquals(P value, FI.UnitApply<P> action) { 
     return (AcceptableReceiveBuilder) super.matchEquals(value 
       , compose(action)); 
    } 

    @Override 
    public 
    <P> AcceptableReceiveBuilder matchEquals(P value, 
              FI.TypedPredicate<P> condition, 
              FI.UnitApply<P> action) { 
     return (AcceptableReceiveBuilder) super.matchEquals(value, condition 
       , compose(action)); 
    } 

    @Override 
    public 
    AcceptableReceiveBuilder matchAny(FI.UnitApply<Object> action) { 
     return (AcceptableReceiveBuilder) super.matchAny(compose(action)); 
    } 

    private 
    <P> FI.UnitApply<P> compose(FI.UnitApply<P> action) { 
     return value -> { 
      action.apply(value); 
      for (FI.UnitApply<Object> it : afterActions) { 
       it.apply(value); 
      } 
     }; 
    } 

    public 
    AcceptableReceiveBuilder thenAccept(FI.UnitApply<Object> action) { 
     afterActions.add(action); 
     return this; 
    } 
} 
+0

ありがとう、私が欲しいもののように見える、私は明日それをテストし、あなたに知らせる –