作为一个课程项目,我试图实现一个(模拟)的筏协议。在这篇文章中,我将不会使用筏术语在所有;相反,我将使用一个简化方法。
该协议由多个服务器运行(例如,5),可以处于三种不同的状态(A,B,C)。服务器从“基本”类型继承了一些状态变量和行为,但它们也都有许多独特的状态变量和方法,并响应不同的消息。在协议的某个点上,处于某种状态的服务器(例如,A)才能变成另一个状态(例如,B)。换句话说,服务器应该:
1.丢失状态A的状态变量和方法,获取状态B的变量和方法,但保留“基本”类型的变量。
1.停止响应发往状态A的消息,开始响应发往状态B的消息。
在Akka中,点1可以使用Receives实现,并变成()。
第2点是需要的,因为,例如,类B的参与者不应该访问类A的参与者的状态变量和方法。这旨在分离关注点,并实现更好的代码组织。
我在实施第2点时面临的问题如下:
- 现在,我的实现只有一个参与者,它包含A和B状态变量和方法。
- 我尝试实现的协议要求每个服务器都必须保持对其他服务器的引用(即其他服务器的ActorRef)。
- 我不能简单地在状态B中生成一个参与者,将“基本”类型的状态变量的值传递给它,然后停止旧的参与者,因为新生成的参与者有一个新的ActorRef,而其他服务器对此一无所知,它们将继续使用旧的ActorRef发送消息(因此,新的参与者将不会收到任何东西,双方都超时)。
规避该问题的一种方式是,新产生的行动者通过向包括其旧的ActorRef的其他行动者发送消息来“通告”其自身。然而,再次由于协议,其他服务器可能暂时不可用(即,它们崩溃),因此它们可能不接收和处理通告。
在这个项目中,我必须使用AbstractActor的扩展,而不是FSM(最终状态机),并且必须使用Java。
是否有任何Akka模式或功能可以解决这个用例?感谢您的见解。下面是一个简化的示例。
public abstract class BaseActor extends AbstractActor {
protected int x = 0;
// some state variables and methods that make sense for both A and B
@Override
public Receive createReceive() {
return new ReceiveBuilder()
.matchEquals("x", msg -> {
System.out.println(x);
x++;
})
.build();
}
}
public class A extends BaseActor {
protected int a = 10;
// many other state variables and methods that are own of A and do NOT make sense to B
@Override
public Receive createReceive() {
return new ReceiveBuilder()
.matchEquals("a", msg -> {
System.out.println(a);
})
.matchEquals("change", msg -> {
// here I want A to become B, but maintain value of x
})
.build()
.orElse(super.createReceive());
}
}
public class B extends BaseActor {
protected int b = 20;
// many other state variables and methods that are own of B and do NOT make sense to A
@Override
public AbstractActor.Receive createReceive() {
return new ReceiveBuilder()
.matchEquals("b", msg -> {
System.out.println(b);
})
.matchEquals("change", msg -> {
// here I want B to become A, but maintain value of x
})
.build()
.orElse(super.createReceive());
}
}
public class Example {
public static void main(String[] args) {
var system = ActorSystem.create("example");
// actor has class A
var actor = system.actorOf(Props.create(A.class));
actor.tell("x", ActorRef.noSender()); // prints "0"
actor.tell("a", ActorRef.noSender()); // prints "10"
// here, the actor should become of class B,
// preserving the value of x, a variable of the "base" kind
actor.tell("change", ActorRef.noSender());
// actor has class B
actor.tell("x", ActorRef.noSender()); // should print "1"
actor.tell("b", ActorRef.noSender()); // should print "20"
}
}
2条答案
按热度按时间58wvjzkj1#
这是一个实现的草图。
1.您可以将每个状态建模为单独的类:
第一个
1.然后,在Actor中,您可以为A和B定义接收函数,并将其初始化为A或B,具体取决于哪一个是初始值
ruarlubt2#
诚然,我的Java是生疏的,但举个例子,这个演员(或者非常类似的东西......)将接收字符串,直到它接收到一个
Lock
消息,之后可以查询它在被锁定之前接收到了多少个不同的字符串。它跟踪接收到的字符串的Set
以执行重复数据删除。在Lock
上,它转换到不包含Set
的第二个Receive
(仅Integer
字段),并忽略String
和Lock
消息。注意,在
Queryable
中,set已经消失了。需要注意的一点是,JavaPartialFunction
通常会在isCheck
设置为true时调用apply
一次,如果该调用没有抛出noMatch()
返回的异常,它将被再次“for真实的”调用,并且isCheck
被设置为false。因此,您需要注意,在isCheck
为true的情况下,除了throw noMatch()
或返回之外,不要执行任何操作。这种模式与Akka Typed(尤其是函数API)中的情况非常相似。
希望这能阐明这种方法,当然,你的老师也有可能不接受这一点,尽管在这种情况下,可能值得用下面的论点来反驳:
AbstractActor
中我也不一定推荐在JavaAkka代码中使用这种方法(字段中带有state的
AbstractActor
更像是Java-y)。