【问题标题】:N-Tier Application DesignN 层应用程序设计
【发布时间】:2026-02-17 18:05:01
【问题描述】:

我对 OOP 中的建筑设计相当陌生(我来自编程机器人,所以有点困难)。我所参与的团队正在创建一个相当大的应用程序,首席项目经理向我们提出了要求,在这些要求中,我们必须在创建模块时使用层。我们使用的技术是用于数据存储的 C# WinForms 和 Oracle。

我的模块由用户管理组成,我试图将逻辑与实现分开,所以我有以下架构:

  • 业务层
  • 数据层
  • 表示层

我将存储库模式和 IoC 与 EF 一起使用,一切看起来和工作正常,但现在我的老板告诉我,我需要将表示层与数据层完全分开。问题在于,我从表示层使用 IoC,如果我想创建一个用户对象,例如,我执行以下操作:

_userRepo.InsertNewUser(new User { props here } ); . 

所以这是不正确的,因为我直接访问 DAL。我的老板告诉我,我需要另一层来隔离此类调用并实施业务规则(?!)

我已经搜索和研究了互联网,但没有发现任何帮助(主要是因为这里的所有内容都在工作中被过滤了)。

我认为我的老板想要一些领域层/服务层,但我不知道如何在当前设计中实现它。我可以毫无问题地发布项目,任何敏感数据都将从代码中删除。

任何帮助将不胜感激。

【问题讨论】:

  • 您尝试这样做的原因是您有两个或更多不同的 PL,或者您的后端 API 被其他应用程序使用。例如,您的 Web、桌面和移动应用程序将使用相同的后端 API。是这样吗?如果不是,你的老板把事情复杂化了,记住 YAGNI。
  • @oleksii 尽管我同意 YAGNI,但解决问题也很重要。例如,如果你想从 EF 更改为其他一些 ORM 框架,你将不得不触摸 BL,这是你不应该...
  • @derape 如果我想从 EF 更改为其他内容,我会在选择 ORM 之前执行此操作。在抽象 ORM 之上构建抽象是一种浪费和过度复杂化。这种抽象还删除了有关 ORM 的特定细节,我认为这些细节相当有用。
  • @oleksii 我认为这个话题没有“黄金法则”,这真的取决于你的应用程序设计和要求等。所以我不能给出详细的“好” " 在这里回答...
  • 我会看看其他同事是怎么做的……

标签: c# .net winforms


【解决方案1】:

我将这个作为答案发布,即使它可能是基于意见的,即使我无法读懂你老板的想法:-)

从根本上说,我认为您的老板想要的是减少所有层之间的依赖关系。您选择执行此操作的架构模式取决于手头的应用程序。你所描述的看起来像three-tier architecture。让我们简要回顾一下三层架构的样子,以及事情应该如何工作:

  • 表示层显示信息并充当用户的边界。
  • 应用程序层(或业务逻辑)控制应用程序的功能。特别是它处理数据并将其分发到其他层。
  • 包含数据访问层 (DAL) 的数据层存储或检索数据。它应该使您的应用程序独立于手头的存储解决方案。它通常适用于数据访问对象 (DAO)。

关于哪一层应该知道其他哪一层,有不同的思想流派。但是从我读到的内容来看,我认为您应该将业务逻辑推广为一种中介。这意味着,业务逻辑知道表示层和数据层,但其他层彼此不知道。我试图通过两个示例场景来澄清这一点:

A.显示现有用户

  1. 业务逻辑向数据层询问特定的User DAO,例如对应于id==123的那个。
  2. 数据层返回User 对象。
  3. 业务逻辑读取存储在User 对象中的值并相应地设置表示层中的值,例如firstNamelastName 等。它转发 User 本身,只转发包含的值。

B.创建新用户

  1. 表示层收集创建新用户所需的所有值。
  2. “提交”时,这些值到达业务逻辑(例如 IoC)。
  3. 业务逻辑告诉数据层使用从表示层获得的值创建一个新的User 对象。
  4. 数据层创建并存储对象。

在不同层之间创建依赖关系的是 DAO。 IE。如果您的表示层要实例化 User 对象,则需要导入属于 DAL 的类(这不是您的老板想要的)。 因此,您可以做的是将表示层和数据层之间的所有通信留给业务逻辑。

作为方案 B 中的替代方案,您还可以让业务逻辑创建 User,以便您的 DAL 方法变得更简单。

正如我一开始所说,没有一种方法可以做到这一点。如果您需要更具体的信息或有其他问题,请随时提出。

【讨论】:

    【解决方案2】:

    感谢您迄今为止提供的所有答案和指导。

    我认为我的老板想要的(我没有联系到他,因为他在 DE 而我在 RO)是完全分离层之间的关注点,比如模型-视图-演示模式,这样表示层 ( UI ) 不会直接访问数据层。它可以通过中间层访问它。

    我向应用程序添加了域/服务层,现在表示层调用服务层,服务层调用业务层并创建用户/组对象。

    接下来的事情是,他说了一些关于这个领域层应该包括的业务规则。这些业务规则是什么,可以举个例子吗?

    我唯一想到的业务规则是一些验证规则,例如:在您调用之前:返回 userRepository.GetUserName(User user) 检查作为非空参数传递的用户对象,或类似的检查。

    所以现在的“机制”是:

    在表示层中,我将 IService 对象注入到构造函数中,然后使用 IService 对象调用方法,例如“GetAllUsers()”。

    IService 本身实际上是用户对象的 Repository 类的“副本”,因此当 IService 对象调用“GetAllUsers()”时,IService 类中有一个确切命名的方法可以执行以下操作:“return _userRepository .GetAllUsers()" - 这样,表示层通过中间层调用对象特定的方法,并且该中间层将直接访问 DL 的某些方法。

    我希望我尽可能清楚地表达自己。如有需要我会提供截图。

    正如我之前所说,我只是开始有建筑设计的经验,因为在机器人领域没有这样的东西,所以请不要扔这么多石头:D

    【讨论】: