在分层体系结构中为存储库定义接口的位置? [英] Where to define the interfaces for a repository in an layered architecture?

查看:144
本文介绍了在分层体系结构中为存储库定义接口的位置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

我正在尝试创建一个简单的应用程序来真正理解整个DDD + TDD +等堆栈。我的目标是在运行时动态注入DAL存储库类。这使我的
域和应用程序服务层可以测试。我计划使用穷人的DI来完成
这个...所以我会在启动附近的一个简单的控制台应用程序中这样做:

I'm trying to create a simple application to really understand the whole stack of DDD+TDD+etc. My goal is to dynamically inject the DAL repository classes at runtime. This keeps my Domain and Application Services layers testable. I plan on using "poor man's DI" to accomplish this for now ... so I would do this in a simple Console application near startup:



    // 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);

为了完成这种依赖注入,我创建了三个存储库接口:

To accomplish this dependency injection, I've created three repository interfaces:


-- ICustomerRepository
-- IOrderRepository
-- IProductRespository

典型的实现:



    namespace SimpleOrder.Domain.Interfaces
    {
        public interface ICustomerRepository
        {
            Customer GetCustomerById(int customerId);
            void SaveCustomer(Customer customer);
        }
    }

**请注意,SaveCustomer引用域中定义的Customer模型类层。这是其他存储库的典型特征。

** Notice that SaveCustomer references the Customer model class defined in the domain layer. This is typical of the other repositories.

但是我不确定应该在哪个项目/层中实现它们。我在解决方案中有5个项目:

HOWEVER I'm not sure which project / layer they should be implemented in. I have 5 projects in a solution:


  1. SimpleOrder.ConsoleClient(演示文稿)
    - 我想注入具体的实现域名从这里作为应用程序

  1. SimpleOrder.ConsoleClient (presentation) -- I want to inject the specific implementation of the domain from here as the application

SimpleOrder.ApplicationFacade(应用程序服务)
- 矮胖的更高级别,更粗糙在域中编排低级方法的渐进方法

SimpleOrder.ApplicationFacade (application services) -- chunky higher-level, coarser-grained methods orchestrating lower-level methods in the domain

SimpleOrder.Contracts
- 用于通信的DTO类演示文稿和应用程序服务之间

SimpleOrder.Contracts -- DTO classes used for communication between presentation and application services

SimpleOrder.Domain(domain / bll)
- 域模型类Customer,Order ,OrderItem,产品

SimpleOrder.Domain (domain / bll) -- domain model classes Customer, Order, OrderItem, Product

SimpleOrder.Repository(dal)
- 实现存储库接口

SimpleOrder.Repository (dal) -- implements the repository interfaces

以下是我的选择我认为:

Here are my options as I see it:

选项1:在SimpleOrder.Contracts中定义存储库接口......

Option 1: Define the repository interfaces in SimpleOrder.Contracts ...

PRO:这是我认为他们应该属于的地方,因为我创建了这个以分享各种关注/层之间的合同。例如,DTO在这里定义。

PRO: this is where I think they should belong because I created this to share contracts between various concerns / layers. ex., DTOs are defined here.

CON:但是每个接口的方法签名都引用了Domain模型类。

这意味着我会必须添加对SimpleOrder.Domain的引用,但是当在另一个项目中引用
SimpleOrder.Contracts时,它必须随身携带
SimpleOrder.Domain。这感觉不对。

CON: however the method signatures in of each interface references Domain model classes.
This means that I would have to add a reference to the SimpleOrder.Domain, but when the SimpleOrder.Contracts is referenced in another project, it will have to carry SimpleOrder.Domain along for the ride. This doesn't feel right.

选项2:与上述情况相同,但我还为每个域模型定义了接口
SimpleOrder.Contracts中的类,所以我可以打破存储库接口与实际模型类的耦合。

Option 2: Same scenario as above, but I ALSO define interfaces for each Domain model class in the SimpleOrder.Contracts so I can break the coupling of the repository interfaces to the actual model classes.

示例:



    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; }
        }
    }

影响:每个域模型类都必须实现其相关的接口。即,

IMPACT: Each domain model class would have to implement his related interface. i.e.,



    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的问题。

PRO: Fixes Option 1's problem.

CON:这会爆炸项目中的文件数量(以及感知的复杂性),因为
每个域类现在都有一个关联的接口。

CON: This explodes the number of files (and the perceived complexity) in the project because each domain class now has an associated interface.

选项3:在SimpleOrder.Domain中定义存储库接口

Option 3: Define the repository intefaces in the SimpleOrder.Domain

IMPACT :为了在运行时从SimpleOrder.ConsoleClient将具体的存储库类注入应用程序服务层(SimpleOrder.ApplicationFacade项目),SimpleOder.ConsoleClient还需要对SimpleOrder.Domain的引用。

IMPACT: In order to inject the concrete repository classes into the application services layer (SimpleOrder.ApplicationFacade project) from the SimpleOrder.ConsoleClient at runtime, SimpleOder.ConsoleClient will ALSO need a reference to SimpleOrder.Domain.

PRO:这个ALSO解决了选项1

PRO: This ALSO solves Option 1

CON:我试图避免直接从表示层引用域层,因为现在表示层可以对域层了解太多。当我将来使用WPF或ASP.NET MVC应用程序替换控制台应用程序时,我会冒第二次和后续表示层实现的风险,试图在模型中调用方法而不是Application Services层。 (但我在选项4中考虑了这一点。)

CON: I was trying to avoid referencing the domain layer from the presentation layer directly because now the presentation layer can know too much about the domain layer. When I replace the console application in the future with a WPF or ASP.NET MVC app in the future, I risk second and subsequent presentation layer implementations from attempting to call methods in the Model instead of the Application Services layer. (However I do consider this in Option 4.)

选项4:将接口放在SimpleOrder.Domain中,然后引用SimpleOrder.Domain来自SimpleOrder.ConsoleClient。

Option 4: Put the interfaces in SimpleOrder.Domain, then reference the SimpleOrder.Domain from the SimpleOrder.ConsoleClient.

PRO:解决了上述所有问题。

PRO: Fixes all the problems above.

CON:这感觉不对,因为我会当我提供
访问SimpleOrder中更高级别的粗块方法时,从表示层
直接访问域层中的低级方法。 ApplicationFacade。

CON: This doesn't feel right because I would be providing access from the presentation layer directly to the lower-level methods in the Domain layer when I should only be providing access to the higher-level chunky methods in the SimpleOrder.ApplicationFacade.

问题
我已经尝试了其中的每一项,但已经确定了选项4,但仍然存在不良品味在我的嘴里谈论它。有更好的选择吗?我在这里走在正确的轨道上吗?

QUESTION I've tried each of these, but have settled on Option 4, HOWEVER that leaves a bad taste in my mouth about it. Is there a better option? Am I on the right track here?

推荐答案

根据我对你的问题的理解,我同意选项4是最好的。应在所有域对象旁边的域层中声明存储库接口。所述接口的实现应该是基础结构层的一部分 - 将您的域层连接到世界的层。看看六角形架构,看看其中的一些动机。

From what I understand of your question, I would agree that option 4 is the best. The repository interfaces should be declared in the domain layer next to all of the domain objects. The implementation of said interfaces should be part of the infrastructure layer - the layer that connects your domain layer to the world. Take a look at the Hexagonal Architecture to see some of the motivation for this.

要解决选项4的con,您不应该将控制台应用视为仅仅是表示层。它还有其他职责,例如作为应用程序的主机和DI中的组合根条款。可能存在控制台应用程序的表示组件,其仅与应用程序服务通信。您还可以使用ASP.NET WebAPI实现的开放主机服务封装应用程序服务。然后表示层将仅引用此服务并从底层域层隐藏。

To address the con of option 4, you shouldn't think of the console app as being solely the presentation layer. It also has other responsibilities, such as being the host for the application and the composition root in DI terms. There could be a presentation component of the console app which only communicates with application services. You can also encapsulate the application service behind an open host service implemented with ASP.NET WebAPI. Then the presentation layer would only reference this service and be hidden from the underlying domain layer.

这篇关于在分层体系结构中为存储库定义接口的位置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆