2016-03-16 25 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

你的回答也很有用,但我只能接受一個。無論如何非常感謝你。 –