【问题标题】:Concerning the Web application architecture what's the difference between domain classes and business classes? [closed]关于 Web 应用程序架构,域类和业务类有什么区别? [关闭]
【发布时间】:2016-02-29 12:55:52
【问题描述】:

我想像这样构建我的asp.net web form 应用程序:

1-DB
2-Data Access Layer(Using ORM[EF])
3-Repository/Unit Of Work (Pattern)
4-Business Layer
5-Service Layer
6-UI

现在我的原始解决方案如下所示:

只有两个类库:

  • DAL (Data Access Layer) 我的 EF 所在的位置。
  • Domain Classes(自动生成)及其等效的部分类。


我关于这个设计的问题:

  1. 我应该把我的business logic放在一个新层还是放在领域类层中,每个业务都属于相关的领域类,或者把我的业务逻辑放在我的网页背后的代码?
  2. 能否有人澄清一下它们之间的区别 设计角度的术语 (POCO,Domain Class,BusinessClass)?

【问题讨论】:

    标签: c# asp.net entity-framework design-patterns


    【解决方案1】:

    我应该将我的业务逻辑放在一个新层中还是只放在每个业务属于相关领域类的领域类层中,还是将我的业务逻辑放在我网页后面的代码中?

    • 您的业务逻辑应该只在您的域/业务类中,不能在其他任何地方;否则,您将面临 贫血域模型 的风险,从长远来看,这通常是一个坏主意。 (有趣的观看here
    • 您的服务层应仅用作业务对象之间的编排点,即它实现流程,而您的业务对象实现流程的各个步骤。

    示例

    所以你可能有一个OrderService 类,它位于服务层,它有方法PlaceOrder 并驱动一个进程来检查Customer 类的状态(a业务对象),将Order(业务类)保存到数据存储(可能通过您的Repository 层),并为客户发送电子邮件确认。 (可能通过另一个服务(请注意,这是一个非常简单的示例,不一定声称是您特定场景的最佳流程)

    有人能澄清一下这些术语在设计角度(POCO、Domain Class、BusinessClass)之间的区别吗?

    • 对于大多数意图和目的而言,“域”和“业务”对象之间几乎没有区别。
    • 两者的存在都是为了对业务领域的解决方案进行建模 - 唯一的区别往往是,如果您遵循强大的领域驱动设计方法,您会倾向于将这些类称为“领域对象”。李>
    • 但除此之外,您可以将它们视为相同的东西 - 它们封装了解决您的业务问题所需的行为和数据。

    POCO 不是 DTO

    POCO 意思是“Plain Old CLR Object”,它基本上是指一个类的实例,它不依赖于任何外部框架,形式为属性或从所述框架继承。

    • 因此,例如,如果您不使用 EF Code First,那么您的 EF 模型类通常会使用 EF 本身在运行时使用的属性进行修饰,以了解什么属性是主键,等等。

    • 通过使用 EF Code First,您可以避免这种情况并在您的代码中使用纯 POCO。

    • POCODTO 经常混为一谈;它们根本不一样!

    • DTO 是一个类,其唯一目的是在边界(层、流程等)之间传输数据,因此通常只是一堆没有业务行为的读/写公共字段或属性。它勉强配得上“对象”分类。

    • 另一方面,POCO 可以同时拥有数据和行为,就像正确的 Object 一样,并且是 Domain(或 Business,如果你愿意的话)类的理想原型。

    一些想法

    我还想指出与您提议的设计相关的其他几件事。

    • 首先,如果您使用的是 EF,则实际上不需要单独的工作单元,因为 DbContext 已经为您封装了工作单元模式。
    • 考虑一下你是否真的需要“层”;例如,除非您的应用程序是一个非常简单的 CRUD 应用程序,否则您可能会从使用 Command/Query 模式中获益更多,而不是将您的架构设计为可能导致结构不灵活的浅层宽层系列,您而是使用面向特征的薄垂直代码切片,这意味着它们可以根据需要尽可能浅或深,从而产生更容易适应的更具凝聚力的设计。有趣的查看此here
    • 如果您使用实体框架,我的诚实建议是使用 Code First;它比经典的.edmx 模型方式灵活得多。
    • 此外,采用 EF 并让它一直渗透到您的服务层是可以的……然后 DTO 开始发挥作用,将这些对象转换为您的 Web 控制器可以发出的传输桶。 (例如使用Automapper)。关于 EF 和 Business Objects 的一些有趣观点here **
    • 我知道这可能与许多典型的“持久无知”建议背道而驰,但根据我的经验,这几乎不是问题(除非您发现自己每隔一周更换一次数据库提供程序!)。

    使用 EF Code First 和采用 DbContext 可以获得的好处包括 - 真正的 POCO 域/业务对象(您可以在单独的程序集中声明您的 BO,以便它们享受持久性无知,但也可以在另一个程序集中(例如您的数据访问层)中单独映射到 EF) - 简化的代码库不会在层之间进行无意义的映射

    **我刚刚意识到我所有的参考文献都是针对同一个人的作品。他不会付钱让我这样做,我发誓:)

    更新

    根据 OP 在循环依赖问题方面的感知问题,这里是一个特定场景的示例代码(用例有点不起作用,只是说明性的)

    public class EmployeeNameService
    {
       readonly IEmployeeRepository _repo;
       public EmployeeNameService(IEmployeeRepsitory repo)
       {
          _repo=repo;
       }
       public string GetEmployeeName(int empID)
       {
          var emp = _repo.GetByID(empID);
          var name = emp.GetEmployeeName();//does some crazy logic based on the Employee state or whatever.
          return name;
       }
    }
    

    现在上面的重点是EmployeeNameService 驻留在服务“层”中,该“层”对存储库层和域对象“层”都有依赖关系(引用)(这不是真正的层,只是包含域/业务类的单独项目)。所以不用担心循环依赖。 当然,Repository 会引用 Domain Objects,这很好,因为它是单向依赖。

    更新 2

    我之前没有提到的一件事是什么时候不遵循上面的建议;如果您有一个非常简单的 CRUD 模型,您正在接受用户输入并将其传递到数据存储中而没有任何“业务逻辑”,那么只需按照最初的计划坚持使用简单的层。但是,一旦有任何业务逻辑,就考虑使用上述概念。

    【讨论】:

    • 很好的答案,非常感谢,但我仍然有些困惑,如果你能帮助我,我将不胜感激。如果我有像GetEmployeeName() 这样的方法并在我的代码中实现这个方法现在在某些页面的后面。我想重构这段代码。我的问题是:这个方法属于哪里?(Employee Domain ClassEmployee Repository)如果我把它放在我的域类中,我必须add a reference of my repository to my Domain Classes !!这将使Circular dependency
    • 嗯,像GetEmployeeName 这样的方法听起来像是属于Employee; EmployeeRepository 在这一点上根本不应该是一个问题,因为您应该已经调用它以将 Employee 从数据库中取出,然后您稍后调用此方法来获取名称(无论出于何种原因)。这有意义吗?
    • 有道理,但是循环依赖呢?我将不得不将repository dll 的引用添加到`域类`!!..
    • 不,你不需要那个——你的服务层会引用这两者,它会推动从存储库获取Employee的过程,然后询问Employee执行GetEmployeeName()...
    • 不一定;应根据您需要实现的流程创建服务类。因此,如果您明白我的意思,您应该发现自己使用通常在 2 个或更多域对象之间进行协调的服务类,以实现一些“更大”的结果。但情况可能并非总是如此。根据经验,整个解决方案中 Service 和 Domain 类之间的 1:1 关系可能表明您的 Domain 类有太多的职责,或者您根本不需要 Domain 类(见我的第二次更新)
    猜你喜欢
    • 2013-07-04
    • 1970-01-01
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 1970-01-01
    相关资源
    最近更新 更多