我是Akka的新手,我已经退出了这项技术,但我无法理解如何在没有业务逻辑的情况下烹饪演员。我们说我需要制作游戏。游戏对玩家有限制,在选择获胜者之后,不能再选择游戏。
public class Game {
private List<String> participants;
private int maxParticipants;
private String winner;
private boolean ended;
public int getMaxParticipants() {
return maxParticipants;
}
public int getParticipantsSize() {
return participants.size();
}
public void addParticipant(String participant) {
participants.add(participant);
}
public boolean isEnded() {
return ended;
}
public void chooseWinner() {
if (ended) {
// do some stuff
}
winner = participants.get(randomNumber);
ended = true;
}
}
演员班:
public class GameActor extends UntypedActor {
private Game game = new Game();
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof AddParticipant) {
// For example there can't be more then two participants.
// I want to have this "if" inside my Game class, not here
if (game.getParticipantsSize() >= game.getMaxParticipants()) {
// do something about it
}
game.addParticipant(message.getParticipant());
}else if (message instanceof ChooseWinner){
// We can't choose winner after game ended. I don't want to have this logic here
game.chooseWinner();
}
}
}
现在我看到了几种方法。在简单的情况下,它们都可以工作,但它们非常有限:
提高异常。仅在负面情况下有效。如果一切正常我 不知道接下来该做什么。捕捉块也是丑陋的,我不知道 想要维护GameFullException,GameEndedException等等。
返回一些值。就像addParticipant中的布尔值一样 成功的。要么限制使用,要么使用另一层ifelse 返回值。
像这样:
public class Game {
private List<Listener> listeners = new ArrayList<>();
public void addListener(Listener listener) {
listeners.add(listener);
}
public void riseEvent(Event event) {
listeners.forEach(l->l.handle(event));
}
}
单个听众是演员:
public class GameActor extends UntypedActor {
private Game game = new Game();
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof AddParticipant) {
game.addParticipant(message.getParticipant());
}else if (message instanceof ChooseWinner){
game.chooseWinner();
}else if( message instanceof Event){
// do something with actor state if needed
}
}
public void handle(Event event) {
self().tell(event, self());
}
}
第三个对我来说似乎是最有趣和最强大的,但是我的模型在这里有一个订阅者并且它是一个演员,然后由模型事件发送给自己似乎是错误的。 当然这个游戏课只是一个例子(我不确定它是否是我的问题的一个很好的例证),这样简单的逻辑可以在演员中完成并且没关系,但是我&# 39; m对如何将业务逻辑与演员分离的原则感兴趣,因为我不认为演员是商业逻辑的好地方,原因有很多。 我对Scala和Java都很感兴趣。一些例子会很棒。
答案 0 :(得分:2)
为什么你的厨师演员没有商业逻辑?封装状态完全是演员擅长的。在你的例子中,我只是删除Game类,并将其字段放在GameActor中,如下所示:
public class GameActor extends UntypedActor {
private List<String> participants;
private int maxParticipants;
private String winner;
private boolean ended;
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof AddParticipant) {
//In my opinion, its perfectly valid to have this here
if (this.participants.size() >= this.maxParticipants) {
// do something about it
}
this.participant.add(message.getParticipant());
}else if (message instanceof ChooseWinner){
//again I why not put the logix here?
if (this.ended)
// Handle this error somehow.
else
this.winner = messag.getWinner();
this.ended = true;
}
}
}
但是如果你想将它分成两个类,你仍然可以,但它们都应该是演员。你可以把它分成一个持有游戏状态的演员(有点像你的游戏类,但这也应该是一个演员)和一个演员在执行状态变化时应该发生副作用的逻辑。 / p>
持有状态的actor可以以不同的方式通知逻辑actor。最简单的方法就是在状态发生变化时回复发件人。如果它始终是发送状态变更请求的actor,那么它也会起作用,当状态发生变化时,它也应该做一些事情。 但是,如果有更多的演员应该对游戏状态的变化做出反应,那么它可以向akkas事件流发送消息,然后所有订阅了该事件的演员都会收到该事件。
答案 1 :(得分:0)
但是演员肯定是放置业务逻辑的地方。 Actor是并发系统的主要业务处理实体。在Erlang中,Actors只是在接收消息时运行的程序。如果您希望中央实体处理消息内容,您必须委托来自演员的消息。
我想提出的另一个评论是关于你的规则3的想法。这是我强烈推荐的,因为这与Akka应该做的完全相反。如果您的游戏需要向GameActor发送消息,您应该让您的Game类扩展Actor本身,然后通过Akka逻辑发送消息。
换句话说,Akka的主要思想就是让业务主体可以轻松地相互通信。然后将业务逻辑与你的演员分开是将Akka解构为不太有用的东西的过程; - )