理解ONION架构和N层架构的区别

4
我正在制作一个基于.Net的应用程序结构。目前,我正在使用MVC 5。以下是系统不同组件的详细信息。
1. 数据库 - 这是底层数据库,将包含数据。
2. OData API - 此API将与数据库交互,并仅执行与数据库相关的操作(CRUD)。我希望此API成为访问和操作数据的唯一平台。它将提供通过不同方式(IQueryable、SQL查询、存储过程)检索数据的功能。
3. 业务服务 - 它将由两部分组成。引擎和API。引擎将具有其中的业务逻辑,其中可能包括业务规则,例如WorkflowEngine将处理所有工作流动作。Resident Workflow Action(CRUD Ops)和Non-Resident Workflow Actions(Submit、Approve、Send Back)。API将在UI和引擎之间通信。然后,引擎将运行业务逻辑并与OData通信。BusinessAPI将是专有API,对这些API的访问将是订阅式的(付费访问)。
4. 用户界面 - 用户界面将基于MVC,并且只与Business APIs交互,并且只负责显示数据并将数据发送回Business APIs。
看起来像是N-Layed架构。如果我引入接口,是否可以与ONION架构相比较。如何将其转换为ONION架构,而不会影响安全性、可扩展性和性能?Dependency DiagramProject Dependency

一些陈旧的老手可能会发现很难区分ONION和尊重SOLID原则的经典三层架构 :) - Joe
2个回答

5

洋葱架构本质上是一种利用依赖注入的n层架构。例如,考虑一个应用程序,它接受一些数字,将它们相加并显示结果。

n层架构:

数据访问层:

public class SqlNumbersGetter
{
    public List<int> GetNumbers() => ...
}

业务逻辑层:

public class Summer
{
    public int GetSum() => new SqlNumbersGetter().GetNumbers().Sum();
}

图形用户界面层:

public class ConsoleDisplayer
{
    public void Display() => Console.WriteLine( new Summer().GetSum());
}

洋葱架构很相似,但我们现在使用接口和依赖注入:
数据访问层:
public interface INumbersGetter
{
     List<int> GetNumbers();
}

public class SqlNumbersGetter : INumbersGetter
{
    public List<int> GetNumbers() => ...
}

业务逻辑层:

public interface ISummer
{
    int GetSum(INumbersGetter numberGetter);
}
public class Summer : ISummer
{
    public int GetSum(INumbersGetter numberGetter) => numberGetter.GetNumbers().Sum();
}

图形用户界面层:

public interface IDisplayer
{
    public void Display(ISummer summer, INumbersGetter numberGetter)
}
public class ConsoleDisplayer : IDisplayer
{
    public void Display(ISummer summer, INumbersGetter numberGetter) => Console.WriteLine(summer.GetSum(numberGetter));
}

然后您的应用程序将实例化所有接口的实例,并将它们全部连接起来。
public void Main()
{
    new ConsoleDisplayer().Display(new Summer(), new SqlNumbersGetter());
}

1
简而言之,洋葱架构可以帮助您构建一个松散耦合的系统,有点像插件系统。您在中心拥有业务逻辑,即核心,其他所有内容(用户界面客户端、第三方库、数据库存储库等)都可以更改,而无需更改此核心层中的任何内容。
这是一种遵循SOLID原则的良好架构:
- 每个部分都具有单一职责,将因同样原因而发生变化的事物聚集在一起。您想将模块与整个组织的复杂性隔离开来,并设计您的系统,使每个模块仅负责满足一个业务功能的需求。 - 开闭原则:编程接口,以便您可以更改实际实现,而不会对客户模块产生连锁反应。
“当有新要求时,您可以通过编写新代码将新功能添加到该系统,而无需修改任何旧代码。功能将仅通过编写新代码添加。” Uncle Bob
  • Liskov替换原则和Interface隔离原则更多的是针对类的构造方式,简而言之:偏爱组合而非继承。如果系统的一个组件只关心类的某个子集方法,则给该组件提供一个接口,其中只包含其所需的子集方法。

  • Dependency Inversion原则:高级策略组件不应依赖于低级详细组件。接口应由高级组件决定,并且详细信息必须符合它。例如,核心层不应依赖于用户界面的实现,用户界面应通过接口依赖于核心。

在这里,您可以找到洋葱架构的详细说明: Victor Rentea - The Art Of Clean Code: https://www.youtube.com/watch?v=c0L7EdsxQ_c

设计模式: onion architecture


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接