2016-03-16 18 views
2

我是Akka的新手,我很喜欢这项技术,但我无法理解如何在没有业务逻辑的情况下为演员做饭。假设我需要制作一款游戏。游戏对玩家有限制,在选择赢家后不能多选。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(); 
     } 
    } 
} 

现在我明白了几种方法。在简单的情况下,他们都可以工作,但他们都非常有限:

  1. 上升例外。仅适用于负面情况。如果一切正常,我 不知道下一步该怎么做。另外catch块是丑陋的,我不想 想维护GameFullException,GameEndedException等等。

  2. 返回一些价值。像addParticipant中的布尔值,如果它是 成功。要么是有限的使用情况,要么是 返回值的另一层ifelse。

  3. 游戏类可以引发事件,我的演员可以订阅它。

像这样:

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

第三人似乎最有趣和最强大的我,但它只是似乎错了,我的模型这里有一个用户,它是一个演员,然后由模型事件发送给自己。 当然,这个游戏课只是一个例子(我不确定它是否是我的问题的一个很好的例证),这样简单的逻辑可以在演员中完成,并且没问题,但我对如何解耦的原理感兴趣演员的业务逻辑,因为我不认为演员是许多原因的商业逻辑的好地方。我对Scala和Java都很感兴趣。一些例子会很棒。

回答

0

但是当然演员放置商业逻辑的地方。参与者是并发系统的主要业务处理实体。在Erlang中,Actor是接收消息时运行的程序。如果你想要一个中央实体处理消息的内容,你必须从演员中委托消息

我想提出的另一个评论是关于你的规则3的想法。这是我强烈建议的,因为这与Akka应该做的事完全相反。如果你的游戏需要发送消息给你的GameActor,你应该让你的Game类扩展Actor本身,然后通过Akka逻辑发送消息。

换句话说,Akka的主要思想就是让业务主体轻松地同时进行交流。将业务逻辑从演员中分离出来,然后是将Akka解构成不是很有用的过程;-)

+0

也许你是对的,我只需要做一点小小的转变。起初我想到演员喜欢另一种同步技术。主要原因是因为我不想在演员中拥有业务逻辑,因为演员很难测试简单的函数和类。但也许这是我需要为简单并发付出的代价。 –

+0

我明白你为什么会这样说,但我认为你是对的。演员很容易测试。发送消息给他们,并测试他们的反应!并发性问题不是你可以避免的 - 如果你想要一个类同时接收消息,扩展Actor类型可能是允许它们参与的最简单的机制。 –

2

为什么你的厨师没有商业逻辑?封装状态是演员擅长的。在你的例子,我只想放下游戏类,并把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; 
    } 
} 

}

你想要的,但如果拆分此为两个类,您还可以,但他们都应该是演员。举例来说,你可以把它分成一个持有游戏状态的演员(有点像你的游戏类,但也应该是一个演员),还有一个演员执行状态变化时副作用应该发生的逻辑。

持有状态的演员可以通过不同的方式通知逻辑演员。最简单的方法就是在状态发生变化时回复发件人。如果发件人始终是发送状态更改请求的主角,并且在状态发生更改时还应该执行某些操作,则这种方法将起作用。 但是,如果有更多的演员对游戏状态的变化做出反应,它可能会向akkas eventstream发送消息,并且所有已订阅该消息的演员将接收该事件。

+0

你的回答也很有用,但我只能接受一个。无论如何非常感谢你。 –