1

我的项目有一个设计问题,我不知道如何解决,我有一个包含存储库的 DAL 层和一个包含“处理器”的服务层。处理器的作用是提供对 DAL 数据的访问并执行一些验证和格式化逻辑。

我的域对象都引用了服务层中的至少一个对象(以从存储库中检索它们的属性值)。但是我面临两个周期性依赖。第一个“循环依赖”来自我的设计,因为我希望我的 DAL 返回域对象——我的意思是它是概念性的——第二个来自我的代码。

  1. 一个领域对象总是依赖于至少一个服务对象
  2. 域对象通过调用服务上的方法从存储库中检索他的属性
  3. 服务的方法调用 DAL
  4. 然而——问题是——当 DAL 完成他的工作时,他必须返回域对象。但是要创建这些对象,他必须注入所需的服务对象依赖项(因为域对象需要这些依赖项)。
  5. 因此,我的 DAL 存储库依赖于服务对象。

这导致了非常明显的周期性依赖。我对如何处理这种情况感到困惑。最后,我正在考虑让我的 DAL 返回 DTO,但它似乎与洋葱架构不兼容。因为 DTO 是在 Infrastructure 中定义的,但 Core 和 Service Layer 不应该知道 Infrastucture。

在此处输入图像描述

此外,我对更改存储库中所有方法的返回类型并不感到兴奋,因为我有数百行代码......

我将不胜感激任何帮助,谢谢!

更新

这是我的代码,可以使情况更清楚:

我的对象(在核心):

public class MyComplexClass1
{
    MyComplexClass1 Property1 {get; set;}
    MyComplexClass2 Property2 {get; set;}
    private readonly IService MyService {get; set;}

    public MyComplexClass1(IService MyService)
    {
       this.MyService = MyService;
       this.Property1 = MyService.GetMyComplexClassList1();
       .....
    }

这是我的服务接口(在核心)

 public interface IService
 {
     MyComplexClass1 GetMyComplexClassList1();
     ...
 }

这是我的存储库接口(在核心中)

public interface IRepoComplexClass1
{
     MyComplexClass1 GetMyComplexClassObject()
     ...
}

现在服务层实现了 IService,DAL 层实现了 IRepoComplexClass1。

但我的观点是,在我的仓库中,我需要构建我的域对象

这是基础设施层

using Core;

public Repo : IRepoComplexClass1
{
   MyComplexClass1 GetMyComplexClassList1()
   {
       //Retrieve all the stuff...
       //... And now it's time to convert the DTOs to Domain Objects
       //I need to write 

       //DomainObject.Property1 = new MyComplexClass1(ID, Service);
       //So my Repository has a dependency with my service and my service has a dependency with my repository, (Because my Service Methods, make use of the Repository). Then, Ninject is completely messed up.
   }

我希望现在更清楚了。

4

1 回答 1

3

首先,像洋葱架构领域驱动设计(DDD) 这样的典型架构指导在设计系统时并不适合所有情况。事实上,不鼓励使用这些技术,除非该领域具有相当的复杂性来保证成本。因此,您正在建模的域非常复杂,以至于它不适合更简单的模式。

恕我直言,洋葱架构和 DDD 都试图实现相同的目标。即,能够为复杂逻辑提供可编程(并且可能易于移植)域,而无需考虑所有其他问题。这就是为什么在 Onion 中,例如,应用程序、基础设施、配置和持久性问题处于边缘。

所以,总而言之,域就是代码。然后它可以利用这些很酷的设计模式来解决手头的复杂问题,而无需担心其他任何事情。

我真的很喜欢 Onion 文章,因为同心屏障的图片与分层架构的想法不同。

在分层架构中,很容易通过层来垂直、上下地思考。例如,您有一个与外界对话的服务(通过 DTO 或 ViewModels),然后该服务调用业务逻辑,最后,业务逻辑向下调用某个持久层以保持系统的状态。

然而,洋葱架构描述了一种不同的思考方式。您可能仍然在顶部有一个服务,但这是一个应用程序服务。例如,ASP.NET MVC 中的控制器知道 HTTP、应用程序配置设置和安全会话。但控制器的工作不仅仅是将工作推迟到较低(更智能)的层。工作是尽快从应用程序端映射到端。简单来说,Controller 调用域,请求执行一段复杂的逻辑,取回结果,然后持久化。控制器是将事物粘合在一起(而不是域)的粘合剂。

因此,域是业务域的中心。没有别的了。

这就是为什么有些人抱怨需要域实体属性的 ORM 工具。我们希望我们的域完全清除除手头问题之外的所有问题。所以,普通的旧对象。

因此,域不直接与应用程序服务存储库对话。事实上,域调用的任何内容都与这些事情无关。域是核心,因此是执行堆栈的末端。

因此,对于一个非常简单的代码示例(改编自 OP):

存储库:

 // it is only infrastructure if it doesn't know about specific types directly
    public Repository<T>
    {
       public T Find(int id)
       {
           // resolve the entity
           return default(T);   
       }
    }

域实体:

public class MyComplexClass1
{
    MyComplexClass1 Property1 {get; }  // requred because cannot be set from outside
    MyComplexClass2 Property2 {get; set;}
    private readonly IService MyService {get; set;}

    // no dependency injection frameworks!
    public MyComplexClass1(MyComplexClass1 property1)
    {
       // actually using the constructor to define the required properties
       // MyComplexClass1 is required and MyComplexClass2 is optional
       this.Property1 = property1;
       .....
    }

    public ComplexCalculationResult CrazyComplexCalculation(MyComplexClass3 complexity)
    {
       var theAnswer = 42;
       return new ComplexCalculationResult(theAnswer);
    }
}

控制器(应用服务):

public class TheController : Controller
{
    private readonly IRepository<MyComplexClass1> complexClassRepository;
    private readonly IRepository<ComplexResult> complexResultRepository;

    // this can use IoC if needed, no probs
    public TheController(IRepository<MyComplexClass1> complexClassRepository, IRepository<ComplexResult> complexResultRepository)
    {
        this.complexClassRepository = complexClassRepository;
        this.complexResultRepository = complexResultRepository;
    }

    // I know about HTTP
    public void Post(int id, int value)
    {
        var entity = this.complexClassRepository.Find(id);

        var complex3 = new MyComplexClass3(value);
        var result = entity.CrazyComplexCalculation(complex3);

        this.complexResultRepository.Save(result);  
    }
}

现在,很快你就会想,“哇,那个控制器做得太多了”。例如,如果我们需要 50 个值来构造MyComplexClass3. 这就是洋葱架构的出色之处。有一种称为Factoryor的设计模式,Builder并且没有应用程序关注点或持久性关注点的约束,您可以轻松实现它。因此,您将这些模式重构到域中(它们成为您的域服务)。

总之,域调用对应用程序或持久性问题一无所知。它是终点,是系统的核心。

希望这是有道理的,我写的比我预期的要多一点。:)

于 2014-04-29T22:45:57.097 回答