如何从Akka 2.5 ReceiveBuilder的每个案例中提取公共代码 [英] How do I extract common code from every case of an Akka 2.5 ReceiveBuilder

查看:458
本文介绍了如何从Akka 2.5 ReceiveBuilder的每个案例中提取公共代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将现有代码库迁移到Akka 2.5.1和Java 8(来自Akka 2.4.8 / Java 7),我的代码如下:

  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();
}
/ *结束类型特定处理* /

/ *开始常用处理* /
doSomethingForAllMessages();
/ *结束常用处理* /
}

在Akka 2.5.1使用 ReceiveBuilder 这看起来像:

  public接收createReceive(){
返回receiveBuilder()
.match(Foo.class,this :: processFoo)
.match(Bar.class,this :: processBar)
.match(Bash.class,this :: processBash)
.match(OtherThing.class,this :: processOtherThing)
.build();
}

...除了这不执行常见处理 doSomethingForAllMessages()。是否有惯用的Java 8 / Akka 2.5.1方法进行一次这种常见处理,而不是将其添加到每个 match()子句中?



更新



我正在寻找类似的东西:



< pre class =lang-java prettyprint-override> 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();
}


解决方案

你实际返回的是一个收到而不是 ReceiveBuilder 。如果你想处理所有可以编写 scala.PartialFunction 的消息,因为接收最终。例如:

 接收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>接收thenAccept(接收原点,FI.UnitApply< T>动作){
返回新接收(thenAccept(origin.onMessage(),action));
}

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

< A,B>功能1< A,选项< B>> thenAccept(Function1< A,Option< B>> fn,
FI.UnitApply< A> action){
return it - > {
选项< B> value = fn.apply(it);
action.apply(it);
返回值;
};
}

IF 您不想操作 scala api可以满足您的需求。出于某种原因,例如: Function1 在先前版本中不是 scala 中的@FunctionalInterface。你可以编写 ReceiveBuilder 。例如:

  public接收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 s。

  public接收createReceive(){
return两个(
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(左边是ReceiveBuilder,右边是ReceiveBuilder){
返回ReceiveBuilder.create()。matchAny(它 - > Stream.of(左,右)
.map(ReceiveBuilder :: build)
.map(Receive :: onMessage)
.forEach(action-> action.apply(it)));
}

thenAccept 行为看起来像属于 ReceiveBuilder ,但您需要付出更多努力来实现它,并在使用时破坏封装 继承

  public接收createReceive(){
返回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();
}



类AcceptableReceiveBuilder扩展了ReceiveBuilder {
private List< FI.UnitApply< Object>> afterActions = new ArrayList<>();

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

@Override
public
< P> AcceptableReceiveBuilder匹配(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(输入
,compose(action));
}

@Override
public
< P> AcceptableReceiveBuilder匹配(类< P>类型,
FI.TypedPredicate< P>条件,
FI.UnitApply< P>操作){
返回this.matchUnchecked(类型,条件,操作);
}

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

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

@Override
public
< P> AcceptableReceiveBuilder matchEquals(P值,
FI.TypedPredicate< P>条件,
FI.UnitApply< P>动作){
return(AcceptableReceiveBuilder)super.matchEquals(value,condition
撰写(动作));
}

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

private
< P> FI.UnitApply< P>撰写(FI.UnitApply< P>动作){
返回值 - > {
action.apply(value);
for(FI.UnitApply< Object> it:afterActions){
it.apply(value);
}
};
}

public
AcceptableReceiveBuilder thenAccept(FI.UnitApply< Object> action){
afterActions.add(action);
返回此;
}
}


I am migrating an existing codebase to Akka 2.5.1 and Java 8 (from Akka 2.4.8 / Java 7) and I have code like:

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 */
}

In Akka 2.5.1 using ReceiveBuilder this looks like:

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();
}

... except that this doesn't do the common processing doSomethingForAllMessages(). Is there an idiomatic Java 8 / Akka 2.5.1 way of doing this common processing once instead of adding it to each match() clause?

Update

I am looking for something like:

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();
}

解决方案

what you actually return is a Receive not a ReceiveBuilder. if you want to process all of the messages you can composing scala.PartialFunction since Receive is final. for example:

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;
    };
}

IF you don't want to operate scala api to achieve your needs. for some reason, e.g: Function1 is not a @FunctionalInterface in scala in prior version. you can composing ReceiveBuilders. for example:

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 you can keeping semantics consistency by combine ReceiveBuilders.

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)));
}

OR the thenAccept behavior looks like belongs to ReceiveBuilder, but you need take more efforts to achieve it, and it break encapsulation when using inheritance.

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;
    }
}

这篇关于如何从Akka 2.5 ReceiveBuilder的每个案例中提取公共代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆