我的项目有一个设计问题,我不知道如何修复,我有一个DAL层,它包含存储库和一个包含“处理器”的服务层。处理器的作用是提供对DAL数据的访问并执行一些验证和格式化逻辑。
我的域对象都引用了服务层中的至少一个对象(从存储库中检索其属性的值)。但是我面临两个周期性的依赖。第一个“循环依赖”来自我的设计,因为我希望我的DAL返回域对象 - 我的意思是它是概念性的 - 第二个来自我的代码。
这导致了非常明显的周期依赖性。我对如何应对这种情况感到困惑。最后我考虑让我的DAL返回DTO但它似乎与洋葱架构不兼容。因为DTO是在基础架构中定义的,但核心和服务层不应该知道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。
但我的观点是,在我的回购中,我需要构建我的域对象
这是Infrascruture Layer
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.
}
我希望现在更清楚了。
答案 0 :(得分:3)
首先,通常,Onion Architecture和Domain Driven Design(DDD)等架构指南在设计系统时并不适合所有情况。实际上,不鼓励使用这些技术,除非域具有显着的复杂性以保证成本。因此,您正在建模的域很复杂,不适合更简单的模式。
恕我直言,洋葱架构和DDD都试图达到同样的目的。也就是说,具有可编程(并且可能是易于移植的)域的能力,用于复杂逻辑,而没有所有其他问题。这就是为什么在Onion中,应用程序,基础架构,配置和持久性问题都处于边缘。因此,总而言之,域只是代码。然后,它可以利用那些很酷的设计模式来解决手头的复杂问题,而不必担心任何其他问题。
我非常喜欢Onion文章,因为同心障碍的图片与分层架构的想法不同。
在分层架构中,通过图层可以轻松地纵向,上下思考。例如,您在顶部有一个服务(通过DTO或ViewModels),然后服务调用业务逻辑,最后,业务logic 调用一些持久层来保持系统状态。
然而,洋葱架构描述了一种不同的思考方式。您可能仍然在顶部有服务,但这是应用程序服务。例如,ASP.NET MVC中的Controller了解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);
}
}
现在,很快你会想到,&#34;哇,控制器做得太多了#34;。例如,如果我们需要50个值来构造MyComplexClass3
,那该怎么办?这就是洋葱建筑的辉煌。有一个名为Factory
或Builder
的设计模式,没有应用程序问题或持久性问题的限制,您可以轻松实现它。因此,您将这些模式重构到域中(并且它们将成为您的域服务)。
总之,域调用都不了解应用程序或持久性问题。它是系统的核心。
希望这是有道理的,我写的比我想的要多一点。 :)