阿卡。如何消除演员内部的业务逻辑?

时间:2016-03-16 21:27:12

标签: java scala 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. 提高异常。仅在负面情况下有效。如果一切正常我 不知道接下来该做什么。捕捉块也是丑陋的,我不知道 想要维护GameFullException,GameEndedException等等。

  2. 返回一些值。就像addParticipant中的布尔值一样 成功的。要么限制使用,要么使用另一层ifelse 返回值。

  3. 游戏类可以升级事件,我的演员可以订阅它。
  4. 像这样:

    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都很感兴趣。一些例子会很棒。

2 个答案:

答案 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解构为不太有用的东西的过程; - )