如何用java实现功能样式的akka​​ actor

时间:2015-12-02 08:39:13

标签: scala functional-programming akka reactive-programming

我在java中实现了简单的反演员:

public class CounterJavaActor extends UntypedActor {

    int count = 0;

    @Override
    public void onReceive(Object message) throws Exception {
        if (message.equals("incr")) {
            count += 1;
        } else if (message.equals("get")) {
            sender().tell(count, self());
        }
    }

}

在课程“scala中的功能反应式编程”课程中,我看到了反函数的功能性实现:

/**
* Advantages:
* state change is explicit
* state is scoped to current behaviour
*/
class CounterScala extends Actor{

  def counter(n: Int) : Receive = {
    case "incr" => context.become(counter(n+1))
    case "get" => sender ! n
  }

  def receive = counter(0)
}

UPD : 我的问题,在java中我不能像scala counter(n+1)那样进行求助函数调用。这意味着什么:

public class CounterJava8Actor extends AbstractActor {
    //counter(0) in scala
    private PartialFunction<Object, BoxedUnit> counter;

    private int n = 0;

    public CounterJava8Actor() {
        counter =
            ReceiveBuilder.
                matchEquals("get", s -> {
                    sender().tell(n, self());
                }).
                matchEquals("inc", s -> {
                    //become(counter(n+1) in scala
                    context().become(counter);
                }).build();
        receive(counter);
    }
}

可以用java实现它的功能风格吗?

1 个答案:

答案 0 :(得分:4)

根据你可以使用的文档成为/不成为java 8

http://doc.akka.io/docs/akka/snapshot/java/lambda-actors.html#become-unbecome

这是从那里复制的示例代码

public class HotSwapActor extends AbstractActor {
  private PartialFunction<Object, BoxedUnit> angry;
  private PartialFunction<Object, BoxedUnit> happy;

  public HotSwapActor() {
    angry =
      ReceiveBuilder.
        matchEquals("foo", s -> {
          sender().tell("I am already angry?", self());
        }).
        matchEquals("bar", s -> {
          context().become(happy);
        }).build();

    happy = ReceiveBuilder.
      matchEquals("bar", s -> {
        sender().tell("I am already happy :-)", self());
      }).
      matchEquals("foo", s -> {
        context().become(angry);
      }).build();

    receive(ReceiveBuilder.
      matchEquals("foo", s -> {
        context().become(angry);
      }).
      matchEquals("bar", s -> {
        context().become(happy);
      }).build()
    );
  }
}

或者您可以使用UntypedActor,如此处的文档中所述

http://doc.akka.io/docs/akka/snapshot/java/untyped-actors.html

public class Manager extends UntypedActor {

  public static final String SHUTDOWN = "shutdown";

  ActorRef worker = getContext().watch(getContext().actorOf(
      Props.create(Cruncher.class), "worker"));

  public void onReceive(Object message) {
    if (message.equals("job")) {
      worker.tell("crunch", getSelf());
    } else if (message.equals(SHUTDOWN)) {
      worker.tell(PoisonPill.getInstance(), getSelf());
      getContext().become(shuttingDown);
    }
  }

  Procedure<Object> shuttingDown = new Procedure<Object>() {
    @Override
    public void apply(Object message) {
      if (message.equals("job")) {
        getSender().tell("service unavailable, shutting down", getSelf());
      } else if (message instanceof Terminated) {
        getContext().stop(getSelf());
      }
    }
  };
}

要了解如何将参数添加到Procedure,您可以看到以下答案:

Akka/Java getContext().become with parameter?

这是java 8的实际解决方案

private PartialFunction<Object, BoxedUnit> counter(final int n) {
    return ReceiveBuilder.
        matchEquals("get", s -> {
            sender().tell(n, self());
        }).
        matchEquals("inc", s -> {
            context().become(counter(n + 1));
        }).build();
}


public CounterJava8Actor() {
    receive(counter(0));
}