我正在设计一个使用域驱动设计概念的系统,我正在努力解决一些问题。 “域”本质上是我工作的公司的业务系统。我也在使用依赖注入。因此,在我的模型中,我有与任何典型业务系统(员工,订单,发票,存款等)相关的事情。现在我正在尝试创建一个现金发布应用程序,用户(也就是员工)可以创建存款并将其应用于未付发票。我遇到的问题是我们还使用外部业务系统(Microsoft Dynamics Nav)来处理我们的会计事务。所以基本上我正在处理两个不同的数据库。因此,对于现金发布应用程序,我已经建模了域对象Deposit和DepositLine。我的域中还有一个IDepositRepository接口,负责持久存款。要从系统获得存款,我只想直接从数据库中获取。但是,为了创建存款,我必须使用Dynamics Nav Web服务,因为某些逻辑会在我不知道的幕后执行。我开始研究Anti Corruption层的概念,在该层中我可以将我的存款对象版本转换为适合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类吗?或者这是应用程序工作流程的一部分?那么这些选项中的哪一个最有意义(如果有的话):
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();
}
}
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();
}
}
感谢您的帮助!
答案 0 :(得分:1)
这是一个合适的设计吗?
对我来说似乎很好。重要的是你的Repository不要忘记Nav的一面,让反腐败层处理它。对于类似的示例,您可能希望查看here。
我知道实现不在域层中,但不是 接口本身使它成为依赖?
您可能有这种感觉,因为您的(假设不可知)服务界面的名称包含“Nav”。要反映可能将Nav 或任何其他ERP作为实现的服务抽象,您应该将其重命名为ICashManagementService
。
如果我有一个IEmailService接口并且想要发送一次电子邮件 存款被张贴,我会将界面注入到 CashPostingDomainService类?或者那是否是其中的一部分 应用程序工作流程?
您的建筑决定是选择其中一个。
选项1.表示发送电子邮件是存款过帐域操作的固有部分。如果您使用域模块并在其他应用程序中重复使用,则发布存款将自动导致发送电子邮件,无论该应用程序是什么。这可能是您在上下文中做的正确的事情,或者您可能希望使事情更通用(例如,在操作后发送反馈但不在域服务中决定此反馈是否应该是邮件,日志文件等。)
选项2.表示在过帐存款后发生的事件序列是特定于应用程序的,即在用例级别而不是业务/域级别。由控制器(或应用程序服务)决定采取哪些动作 - 发送电子邮件或其他任何内容。因此,基于您的域层的不同应用程序可能决定采取不同的操作。这也意味着如果其中一些应用程序选择发送邮件,这些应用程序之间可能存在代码重复。