C# 企业设计模式问题

C# 企业设计模式问题,c#,.net,architecture,C#,.net,Architecture,我脑子里想的是在高层次上构建一个系统 假设您有一个具有以下层的系统: 用户界面 服务层 域模型 数据存取 服务层用于填充域模型中的对象图。为了避免耦合,域模型将不支持持久性,并且不会依赖于任何数据访问层 然而,使用这种方法,域模型中的一个对象如何能够调用其他对象,而不能够使用持久性加载它们,从而将所有对象耦合在一起——这是我试图避免的 e、 g.订单对象需要检查库存对象,并且显然需要告诉库存对象以某种方式加载,或者以某种方式填充它 有什么想法吗?您可以从服务层注入任何依赖项,包括填充的对象图

我脑子里想的是在高层次上构建一个系统

假设您有一个具有以下层的系统:

  • 用户界面
  • 服务层
  • 域模型
  • 数据存取
服务层用于填充域模型中的对象图。为了避免耦合,域模型将不支持持久性,并且不会依赖于任何数据访问层

然而,使用这种方法,域模型中的一个对象如何能够调用其他对象,而不能够使用持久性加载它们,从而将所有对象耦合在一起——这是我试图避免的

e、 g.订单对象需要检查库存对象,并且显然需要告诉库存对象以某种方式加载,或者以某种方式填充它


有什么想法吗?

您可以从服务层注入任何依赖项,包括填充的对象图

我还想补充一点,存储库可以是一个依赖项—如果您已经为存储库声明了一个接口,那么您可以在不添加任何耦合的情况下对其进行编码。

要将其解耦,您必须:“编程到‘接口’,而不是‘实现’。”(Gang of Four 1995:18)

以下是有关该主题的一些链接:


在谷歌上搜索“程序到接口,而不是实现”将产生许多有用的资源。

您应该查看在系统中使用接口的类型和模式。

一种方法是在数据层和域模型之间有一个映射层

看看映射、存储库和外观模式


基本思想是,一边是数据访问对象,另一边是域对象。

让域模型层为您需要调用的方法定义接口,为这些方法需要返回的对象定义POCO。然后,数据层可以通过从数据存储中提取数据并将其映射到域模型POCOs来实现这些接口


任何需要特定数据访问服务的域级类都可以通过构造函数参数依赖于接口。然后,您可以利用依赖项注入框架来构建依赖关系图,并在需要的地方提供正确的接口实现。

在编写大量代码之前,为了将您可能想问自己的所有问题分开,请回答以下几个问题:

  • 领域模型是否真正独立于DAL?是的,我是认真的,你们应该考虑一下这一点,因为对于一个现有的项目来说,一个RDBMS实际上被替换为另一个是非常罕见的。坦率地说,编写应用程序时使用的语言要比数据库本身更常见

  • 这种分离到底给你买了什么?同样重要的是,你失去了什么?关注点分离(SoC)是一个很好的术语,被广泛使用。然而,大多数人很少理解为什么他们一开始就关心分离

  • 我之所以提出这些问题,是因为应用程序往往可以从与底层数据模型的更紧密耦合中获益。由于代码生成的性质,大多数ORM几乎强制执行紧密耦合。我见过很多假定的SoC项目在测试过程中崩溃,因为有人在表中添加了一个字段,DAL没有重新生成。。。我想,这种做法有违目的

    另一个因素是业务逻辑应该存在于何处?毫无疑问,有强有力的论据支持将大量BL放入实际数据库本身。同时,在某些情况下,BL需要位于域类中或非常靠近域类。以这种方式传播BL,你真的能把这两项分开吗?即使是那些讨厌将BL放入数据库的人,也会转而使用标识键,让DB强制执行引用完整性,这也是业务逻辑


    不知道更多,我建议您考虑扁平化数据访问和域模型层。您可以转向“提供者”或“工厂”类型的体系结构,在这种体系结构中,服务层本身并不关心底层访问,但工厂会处理所有这些。只是一些激进的想法

    到目前为止,我已经看到应用程序可以很好地分为三层:表示-->逻辑-->数据--和实体(或业务对象)。在逻辑层的情况下,您可以使用一些模式,例如事务脚本域模型,我假设您使用的是最后一种模式。域模型可以使用数据映射器与数据层交互并创建业务对象,但也可以使用表模块模式


    所有这些模式都在Marttin的Fowler企业应用程序体系结构模式一书中进行了描述。就我个人而言,我使用事务脚本是因为它比Domanin模型更简单。一个解决方案是使数据访问层对域实体进行子类化(例如,使用),并将自身注入到它返回的派生实例中

    这样,您的域实体类仍然不知道持久性,而应用程序使用的实例仍然可以命中数据库以延迟加载辅助数据

    话虽如此,这种方法通常要求您对ORM的体系结构进行修改,例如将某些方法标记为虚拟方法,添加其他不必要的默认构造函数,等等


    此外,这通常是不必要的——特别是对于没有繁琐的性能要求的业务应用程序,您可以考虑迫切地加载所有相关数据:只需将库存项按顺序发送。

    < P> >我觉得这与以前的A是不同的。
    interface IDBModel {
      DataTable LoadUser(Int32 userId);
    }
    
    class MyDbModel : IDBModel {
      DataTable LoadUser(Int32 userId) {
        // make the appropriate DB calls here, return a data table
      }
    }
    
    class User {
      public User(IDBModel dbModel, Int32 userId) {
        DataTable data = dbModel.LoadUser(userId);
        // assign properties.. load any additional data as necessary
      }
    // You can do cool things like call User.Save() 
    // and have the object validate and save itself to the passed in 
    // datamodel.  Makes for simpler coding.
    }
    
    class MyServiceLayer {
      public User GetUser(Int32 userId) {
        IDBModel model = new MyDbModel();
    
        return new User(model, userId);
      }
    }