1

我正在使用领域驱动的设计概念设计一个系统,但我正在努力解决一些问题。“域”本质上是我工作的公司的业务系统。我也在使用依赖注入。所以,在我的模型中,我有与任何典型业务系统相关的东西(员工、订单、发票、存款等)。现在我正在尝试创建一个现金过帐应用程序,用户(又名员工)可以在其中创建存款并将其应用于未付发票。我遇到的问题是我们还使用外部业务系统(Microsoft Dynamics Nav)来处理我们的会计交易。所以本质上我正在处理两个不同的数据库。因此,对于现金过帐应用程序,我对域对象 Deposit 和 DepositLine 进行了建模。我的域中还有一个 IDepositRepository 接口,负责保存存款。要从系统中获取存款,我只想直接从数据库中获取。但是,为了创建存款,我必须使用 Dynamics Nav Web 服务,因为在幕后执行某些我不知道的逻辑。我开始研究反腐败层的概念,在该层中,我可以将我的存款对象版本转换为适合 Web 服务的存款对象。所以这就是我现在所设想的:为了创建存款,我必须使用 Dynamics Nav Web 服务,因为在幕后执行某些我不知道的逻辑。我开始研究反腐败层的概念,在该层中,我可以将我的存款对象版本转换为适合 Web 服务的存款对象。所以这就是我现在所设想的:为了创建存款,我必须使用 Dynamics Nav Web 服务,因为在幕后执行某些我不知道的逻辑。我开始研究反腐败层的概念,在该层中,我可以将我的存款对象版本转换为适合 Web 服务的存款对象。所以这就是我现在所设想的:

领域层

- Models
    - Deposit
    - DepositLine
- Repositories
    - IDepositRepository

基础设施层

- Data
    - Repositories
        - DepositRepository
- DynamicsNav
    - Services
        - INavCashManagementService
    - Translators
        - IDepositTranslator
    - Adapters
        - INavAdapter

现在我想我可以像这样实现 DepositRepository :

public class DepositRepository
{
    private INavCashManagementService navCashManagementService;

    public DepositRepository(INavCashManagementService navCashManagementService)
    {
        this.navCashManagementService = navCashManagementService;
    }

    public Deposit GetDeposit(int id)
    {
        // use nhibernate to get directly from the database
    }

    public void SaveDeposit(Deposit deposit)
    {
        this.navCashManagementService.CreateDeposit(deposit);
    }
}

首先,这是一个合适的设计吗?我的下一个问题是用户还必须“发布”存款。Nav Web 服务也必须用于运行发布例程。但是,这更像是一个业务流程而不是持久性问题,所以我认为它不适合存储库。所以我想知道我应该如何/在哪里调用发布程序。我应该像这样创建域服务:

public class CashPostingDomainService
{
    private INavCashManagementService navCashManagementService;

    public CashPostingDomainService(INavCashManagementService navCashManagementService)
    {
        this.navCashManagementService = navCashManagementService;
    }

    public void PostDeposits()
    {
        this.navCashManagementService.PostDeposits();
    }
}

我对域驱动设计的一个困惑是外部依赖。CashPostingDomainService 类现在对 Nav 没有外部依赖吗?我知道实现不在域层中,但是接口本身不是使其成为依赖项吗?发送电子邮件等其他技术问题也是如此。如果我有一个 IEmailService 接口,并且想在存款过帐后发送电子邮件,我会将该接口注入 CashPostingDomainService 类吗?或者这会是应用程序工作流程的一部分吗?那么这些选项中的哪一个最有意义(如果有的话):

1

public class DepositController
{
    private ICashPostingDomainService cashPostingDomainService;
    private IEmailService emailService;

    public DepositController(
        ICashPostingDomainService cashPostingDomainService, 
        IEmailService emailService)
    {
        this.cashPostingDomainService = cashPostingDomainService;
        this.emailService = emailService;
    }

    public void PostDeposits()
    {
        this.cashPostingDomainService.PostDeposits();
        this.emailService.NotifyDepositsPosted();
    }
}

2

public class DepositController
{
    private ICashPostingDomainService cashPostingDomainService;

    public DepositController(
        ICashPostingDomainService cashPostingDomainService)
    {
        this.cashPostingDomainService = cashPostingDomainService;
    }

    public void PostDeposits()
    {
        this.cashPostingDomainService.PostDeposits();
    }
}

public class CashPostingDomainService
{
    private INavCashManagementService navCashManagementService;
    private IEmailService emailService;

    public CashPostingDomainService(
        INavCashManagementService navCashManagementService,
        IEmailService emailService)
    {
        this.navCashManagementService = navCashManagementService;
        this.emailService = emailService;
    }

    public void PostDeposits()
    {
        this.navCashManagementService.PostDeposits();
        this.emailService.NotifyDepositsPosted();
    }
}

谢谢您的帮助!

4

1 回答 1

1

这是一个合适的设计吗?

对我来说似乎很好。重要的是您的存储库要忘记导航方面的事情,并让反腐败层处理它。您可能想在这里查看类似的示例。

我知道实现不在域层中,但是接口本身不是使其成为依赖项吗?

您可能会有这种感觉,因为您的(假设是不可知的)服务接口的名称包含“Nav”。为了反映可以将 Nav任何其他 ERP 作为实现的服务抽象,您应该将其重命名为ICashManagementService.

如果我有一个 IEmailService 接口,并且想在存款过帐后发送电子邮件,我会将该接口注入 CashPostingDomainService 类吗?或者这会是应用程序工作流程的一部分吗?

选择其中一个是您的架构决定。

选项 1. 意味着发送电子邮件是存款发布域操作的固有部分。如果您使用您的域模块并在另一个应用程序中重复使用它,那么发布存款将自动导致发送一封电子邮件,无论该应用程序是关于什么的。在您的上下文中,这可能是正确的做法,或者您可能想让事情变得更通用(例如,在操作后发送反馈,但在域服务中没有决定该反馈是否应该是邮件、日志文件等.)

选项 2. 意味着在发布存款后发生的事件序列是特定于应用程序的,即在用例级别而不是业务/域级别。由控制器(或应用程序服务)决定采取哪些操作 - 发送电子邮件或其他任何内容。因此,基于您的领域层的不同应用程序可能会决定采取不同的操作。如果其中几个选择发送邮件,这也意味着这些应用程序之间可能存在代码重复。

于 2012-10-04T14:06:21.870 回答