命令设计模式中的业务逻辑

时间:2018-02-18 19:20:51

标签: oop design-patterns domain-driven-design

我使用命令设计模式来处理玩家的行为。

例如,下面是处理骰子滚动的命令。

const boundary = '-------314159265358979323846';
        const delimiter = "\r\n--" + boundary + "\r\n";
        const close_delim = "\r\n--" + boundary + "--";
        const metadata = {
            'name': 'myFile.pdf',
            'mimeType': 'application/pdf\r\n\r\n'
        };

        const multipartRequestBody = delimiter +
            'Content-Type: application/json\r\n\r\n' +
            JSON.stringify(metadata) +
            delimiter +
            'Content-Encoding: ' + 'base64\r\n' +
            'Content-Type: ' + 'application/pdf\r\n\r\n' +
            data +
            close_delim;

        const request = auth.request({
            url: 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart',
            method: 'post',
            headers: {
                'Content-Type': `multipart/related; boundary=${boundary}`,
                'Content-Length': multipartRequestBody.length
            },
            data: multipartRequestBody
        });
        const response = await request;
  1. 在命令中存储其他业务逻辑是否是个好主意?
  2. 我应该直接从roll命令调用另一个命令,还是我需要避免它?在命令中抛出事件的想法对我来说似乎更好。你觉得怎么样?
  3. 谢谢!

2 个答案:

答案 0 :(得分:2)

DDD中最常用的命令模式形式(来自CQRS的命令模式)与Go4命令模式不同。它只是一个没有execute()方法的DTO。

在DDD中,应用程序逻辑位于命令处理程序/应用程序服务中,而不是命令本身。

请注意,您当前在execute()中拥有的大部分逻辑都是域逻辑,甚至不应该在命令处理程序中。 Go to jailNext playerMove forward - 这些看起来像应该位于域层中的域规则。

  

我应该直接从roll命令调用另一个命令吗?   需要避免吗?似乎在命令中抛出事件的想法   对我来说更好你觉得怎么样?

这取决于您是否认为后续行动是主要行动的一部分或间接后果。间接命令通常作为单独事务的一部分执行。

答案 1 :(得分:0)

当您希望将请求封装为对象时,Command模式非常有用。这允许您在实例化时将参数传递给它们,将它们组合在一起(将它们作为块执行),记录它们,甚至撤消它们。

我还没有看到你需要这个的原因。

  

在命令中存储其他业务逻辑是否是个好主意?

存储业务逻辑(在表示层中)很糟糕的一个原因是,如果要添加应用程序的另一个版本(例如,移动版本),则必须在新应用程序中重复业务逻辑代码(在其表示层)。此外,维护和测试业务逻辑更加困难,因为它实际上并没有很好地封装(它已经散布)。

但是,在这里,您已将其中的一些封装在Command对象中,这可能并不坏(取决于您在哪里看到此代码)。对于Monopoly游戏,你会有多个客户(不同的表示层吗?)或者这是一个宠物项目(一个实现)?如果将有不同的表示层,那么最好将域逻辑保留在它们之外。你的示例代码中没有任何东西(但我对PHP不好),而且看起来过于依赖于演示,所以它可能没问题。

通常,如果您尝试封装域逻辑,则GoFFaçade模式很有用。您在域层中有一个处理高级操作的Façade类(例如rollAndMove($dice))。看来你已经在骰子卷上使用了Façade。玩家可以选择是一个扮演外墙卷的类,因为转向的域逻辑对于该类(IMO)来说是一个合理的责任。当然,如果Player最终使用了太多方法,那么为Façade使用一个单独的类可能会更好。

  

在命令中抛出事件的想法对我来说似乎更好。你觉得怎么样?

我没有看到组合这两种模式的问题,但也许你真的不需要Command的目的是什么?

你是对的execute()代码很短(只需调用Facade的方法)。但是,使用Command对象可以保存游戏的状态(例如,GoF Memento模式),如果您想稍后撤消命令,或者如上所述,您可以以标准方式记录信息等。如果您不喜欢不需要那些东西,我会避免使用Command,因为它增加了复杂性而没有模式的意图。