我如何随机使用CQRS +事件采购

时间:2016-08-23 06:24:37

标签: c# mongodb cqrs event-sourcing

我写了我的项目,这是论坛的游戏黑手党。我使用CQRS Event Sourcing + MongoDB。当游戏开始时,游戏需要给每个玩家一个随机角色。如何实现它,如果聚合根将被应用事件,例如,#DB;给出的角色",来自DB(不是事件,现在已经保存),总是会调用随机函数,这将是返回不同的结果?

2 个答案:

答案 0 :(得分:1)

通常你会有一个触发某些域行为的命令(即分配随机角色)然后该角色将被保存在数据库中的一个事件中,即。 RoleAssigned。当玩家下次通过重播事件恢复游戏时,这将保留角色。你不会在处理事件的代码中分配随机角色,它将在命令处理程序中完成,而不会重放。

public void Handle<StartGameCommand>()
{
     var player = someEventSourcedPlayerRepository.GetOrCreateOrWhatever();
     player.assignRole(); // randomly assigns the role and creates event RoleAssigned
     someEventSourcedPlayerRepository.Save(); // saves events to db
}

在上面的代码中,玩家将拥有一个角色扮演的事件。当您下次加载玩家时,他们的角色将来自该事件。你不要再次调用player.assignRole。

答案 1 :(得分:0)

  

我如何实现它,如果聚合根将被应用事件,例如,“给出的角色”,来自DB(不是事件,现在已经保存),总是会调用随机函数,这将是返回不同的结果?

创建事件和应用事件是不同的代码路径。应用事件时没有“思考”,因为聚合在创建事件时已经考虑过了。您在申请时需要做的就是忠实地更新您的州。

也就是说,在应用事件时强制执行规则并不是聚合的工作。

所以你的历史看起来像是

GameStarted()
RoleAssigned(Alice, Innocent)
RoleAssigned(Bob, Innocent)
RoleAssigned(Charlie, Mafia)
...

请注意,没有随机的事情可做;你可以补充你的游戏状态,而不必担心这些事件是否最初描述了随机分配 - 因为分配发生在过去,分配完全由现在确定。

当聚合做出决定时,赋值的随机位属于写路径

void assignRole(Player p) {
    Role role = getRandomRole();
    this.apply( RoleAssigned(p, role) );
}

<强>跟进

  

我应该如何更改我的代码?

class GameEventHandler { 
    public void Handle(GameStartedEvent message) { 
        var randomRoles =_randomizer.GetRandomRoles(); 

        foreach(user in userAggregates) { 
            user.RoleAssign(new AssignRoleCommand(randomRoles[i] ));
        } 
    } 
}

事件处理程序中的决策代码是“代码味道”;这是某个地方出了问题的线索。当聚合处理命令时,应在模型中进行选择。

对于像Mafia这样的地方,您需要在角色之间保持适当的平衡,并且需要担心在分配角色时使用的变体规则,我希望Game聚合拥有该角色作业决定。因此,随机分配将在StartGameCommand处理程序中发生,并且可能看起来像这样

class Game {
    public void startGame () {
        this.apply(GameStarted());

        var randomRoles =_randomizer.GetRandomRoles(); 

        foreach(userId in this.players) {
            this.apply(RoleAssigned(userId, randomRoles[i]);
        }
    }
}

我们之前看到的事件列表都在这里,是作为运行一个命令的结果写的(这意味着所有事件都会在一次事务中写入事件存储区)。

另一方面,如果你真的需要每个用户聚合来负责分配它的角色,那么这里的逻辑就会像这样分解

class Game {
    public void startGame () {
        this.apply(GameStarted(this.players));
    }
}

class User {
    public void assignRole () {
        this.apply(RoleAssigned(this.id, _randomizer.getRandomRole());
    }
}

并且您的事件处理程序将桥接这两者,而不了解随机角色。

class GameEventHandler { 
    public void Handle(GameStartedEvent message) { 
        foreach(userId in message.players) { 
            dispatch(AssignRoleCommand(userId));
        } 
    } 
}

事件处理程序就像经理,他们什么都不做,他们只是将工作委托给其他人

相关问题