Bob*_*bor 12 domain-driven-design interface ddd-repositories layer n-tier-architecture
背景
我正在尝试创建一个简单的应用程序来真正理解整个DDD + TDD +等堆栈.我的目标是在运行时动态注入DAL存储库类.这使我的域和应用程序服务层可以测试.我计划使用"穷人的DI"来实现这一目标...所以我会在启动附近的一个简单的控制台应用程序中执行此操作:
// Poor man's DI, injecting DAL repository classes at runtime
var productRepository = new SimpleOrder.Repository.ProductRespository();
var customerRepository = new SimpleOrder.Repository.CustomerRepository();
var orderRepository = new SimpleOrder.Repository.OrderRepository();
// Constructor injection into this class in the Application Services layer,
// SimpleOrder.ApplicationFacade
OrderEntry oe = new OrderEntry(customerRepository, orderRepository, productRepository);
为了实现这种依赖注入,我创建了三个存储库接口:
-- ICustomerRepository -- IOrderRepository -- IProductRespository
一个典型的实现:
namespace SimpleOrder.Domain.Interfaces
{
public interface ICustomerRepository
{
Customer GetCustomerById(int customerId);
void SaveCustomer(Customer customer);
}
}
**请注意,SaveCustomer引用了域层中定义的Customer模型类.这是其他存储库的典型.
但是我不确定应该在哪个项目/层实施.我在解决方案中有5个项目:
SimpleOrder.ConsoleClient(presentation) - 我想从这里注入域的特定实现作为应用程序
SimpleOrder.ApplicationFacade(应用程序服务) - 在域中编排较低级别方法的较高级别,粗粒度方法
SimpleOrder.Contracts - 用于表示和应用程序服务之间通信的DTO类
SimpleOrder.Domain(domain/bll) - 域模型类Customer,Order,OrderItem,Product
SimpleOrder.Repository(dal) - 实现存储库接口
我看到以下是我的选择:
选项1:在SimpleOrder.Contracts中定义存储库接口...
PRO:这是我认为他们应该属于的地方,因为我创建了这个以分享各种关注/层之间的合同.例如,DTO在这里定义.
CON:但是每个接口的方法签名都引用了Domain模型类.
这意味着我必须添加对SimpleOrder.Domain的引用,但是当在另一个项目中引用SimpleOrder.Contracts时,它必须随身携带SimpleOrder.Domain.这感觉不对.
选项2:与上面相同的场景,但我也为SimpleOrder.Contracts中的每个Domain模型类定义接口,因此我可以打破存储库接口与实际模型类的耦合.
例:
namespace SimpleOrder.Domain.Interfaces
{
public interface ICustomerRepository
{
ICustomer** GetCustomerById(int customerId);
void SaveCustomer(ICustomer customer);
}
public interface ICustomer
{
int CustomerId { get; set; }
string Name { get; set; }
System.Collections.Generic.List Orders { get; }
}
}
影响:每个域模型类都必须实现其相关接口.即
public class Customer : SimpleOrder.Domain.Interfaces.ICustomer
{
public Customer()
{
_orders = new List();
}
public int CustomerId { get; set; }
public string Name { get; set; }
private List _orders;
public virtual List Orders {
get { return _orders; }
}
}
PRO:修复了选项1的问题.
CON:这会爆炸项目中的文件数量(以及感知的复杂性),因为每个域类现在都有一个关联的接口.
选项3:在SimpleOrder.Domain中定义存储库接口
影响:为了在运行时从SimpleOrder.ConsoleClient将具体的存储库类注入应用程序服务层(SimpleOrder.ApplicationFacade项目),SimpleOder.ConsoleClient还需要对SimpleOrder.Domain的引用.
PRO:此ALSO解决了选项1
CON:我试图避免直接从表示层引用域层,因为现在表示层可以对域层了解太多.当我将来使用WPF或ASP.NET MVC应用程序替换控制台应用程序时,我冒险尝试在模型中调用方法而不是应用程序服务层,从而冒第二次和后续的表示层实现.(但我在选项4中考虑过这一点.)
选项4:将接口放在SimpleOrder.Domain中,然后从SimpleOrder.ConsoleClient引用SimpleOrder.Domain.
PRO:解决了上述所有问题.
CON:这感觉不对,因为当我只提供对SimpleOrder.ApplicationFacade中更高级别的粗略方法的访问时,我将提供从表层直接访问域层中的低级方法的访问权限.
问题 我已尝试了其中的每一个,但已经确定了选项4,但是在我的嘴里却留下了不好的味道.有更好的选择吗?我在这里走在正确的轨道上吗?