数据映射器、表数据网关(Gateway)、数据访问对象(DAO)和存储库模式之间的区别是什么?

我试图温习我的设计模式技能,我很好奇这些模式之间有什么不同?它们看起来都是一样的——封装特定实体的数据库逻辑,这样调用代码就不知道底层的持久层。根据我的简短研究,它们都典型地实现了标准的 CRUD 方法,并抽象出特定于数据库的细节。

除了命名约定(例如 CustomerMapper 对 CustomerDAO 对 CustomerGateway 对 CustomerRepository) ,如果有区别的话,还有什么区别呢?如果有区别,你什么时候会选择其中一个?

在过去,我会编写类似于下面的代码(简化,自然-我通常不会使用公共属性) :

public class Customer
{
public long ID;
public string FirstName;
public string LastName;
public string CompanyName;
}


public interface ICustomerGateway
{
IList<Customer> GetAll();
Customer GetCustomerByID(long id);
bool AddNewCustomer(Customer customer);
bool UpdateCustomer(Customer customer);
bool DeleteCustomer(long id);
}

并具有一个 CustomerGateway类,该类为所有方法实现特定的数据库逻辑。有时候我不会使用一个接口并使 CustomerGateway 上的所有方法都是静态的(我知道,我知道,这使得它的可测试性更低) ,所以我可以这样调用它:

Customer cust = CustomerGateway.GetCustomerByID(42);

对于 Data Mapper 和 Repository 模式,这似乎是相同的原则; DAO 模式(我认为这与 Gateway 是相同的)也似乎鼓励特定于数据库的网关。

我错过了什么吗?有3-4种不同的方法来做同样的事情似乎有点奇怪。

32168 次浏览

你说得对。挑一个你最熟悉的。我想指出一些可能有助于澄清的事情。

表数据网关主要用于单个表或视图。它包含所有的选择、插入、更新和删除。所以在您的情况下,Customer 是一个表或视图。因此,表数据网关对象的一个实例处理表中的所有行。通常这与每个数据库表一个对象有关。

虽然 Data Mapper 更加独立于任何域逻辑,而且耦合程度更低(尽管我相信要么存在耦合,要么没有耦合)。它只是一个中间层,用于在对象和数据库之间传输数据,同时保持它们彼此独立,以及映射器本身。

因此,通常在映射器中,可以看到插入、更新、删除等方法,在表数据网关中可以找到 getcustomerbyId、 getcustomerbyName 等。

数据传输对象不同于上述两种模式,主要是因为它是一种分布式模式,而不是上述两种模式的数据源模式。使用它主要是当您使用远程接口,并需要使您的呼叫少聊天,因为每个呼叫可能会变得昂贵。因此,通常设计一个 DTO,它可以通过连接进行序列化,将所有数据带回服务器,以便应用进一步的业务规则或处理。

我对存储库模式不是很熟悉,因为我到现在还没有机会使用,但是我会看看其他人的答案。

在软件设计领域有一种趋势(至少我是这么认为的) ,就是为众所周知的旧事物和模式创造新的名称。当我们有了一个新的范例(可能与已有的范例略有不同) ,它通常会为每一层提供一整套新的名称。所以“业务逻辑”变成了“服务层”,仅仅因为我们说我们做 SOA,而 DAO 变成了仓库,仅仅因为我们说我们做 DDD (每一个实际上都不是什么新的和独特的东西,但是再次重申: 在同一本书中收集的已知概念的新名称)。因此,我并不是说所有这些现代范式和缩略语的意思完全一样,但你真的不应该对此过于偏执。大部分都是相同的模式,只是来自不同的家庭。

您的示例术语: DataMapper、 DAO、 DataTableGateway 和 Repository 都有相似的用途(当我使用一个时,我希望得到一个 Customer 对象) ,但是意图/含义和结果实现不同。

一个 仓库 “除了具有更复杂的查询能力外,其行为类似于集合”[ 埃文斯,领域驱动设计] ,可以被认为是一个 “内存外观中的对象”(知识库讨论)

A DataMapper “在对象和数据库之间移动数据,同时保持它们彼此独立,映射器本身”(Fowler PoEAA Mapper)

TableDataGateway”数据库表的网关(封装对外部系统或资源的访问的对象)。一个实例处理表中的所有行”(Fowler,PoEAA,TableDataGateway)

允许 “独立于使用数据的代码更改的数据访问机制”(太阳蓝图)的 DAO “将数据资源的客户端接口与其数据访问机制分离/将特定数据资源的访问 API 改编为通用客户端接口”

存储库看起来非常通用,没有暴露数据库交互的概念。 DAO 提供了一个接口,允许使用不同的底层数据库实现。 TableDataGateway 特别是围绕单个表的瘦包装器。 DataMapper 充当中介,使 Model 对象能够独立于数据库表示形式(随着时间的推移)而发展。

数据映射器与表数据网关 长话短说:

  • Data Mapper 将接收 Domain Model 对象(Entity)作为参数,并使用它来实现 CRUD 操作
  • Table Data Gateway 将接收方法的所有参数(作为原语) ,并且不知道有关 Domain Model 对象(Entity)的任何信息。

    最终,它们都将充当内存对象和数据库之间的中介。

  • 以下只是我的理解。

    TableGateWay/RowDataGateWay : 在这个上下文中,Gateway 引用了一个特定的实现,该实现将每个“域对象”映射到每个“域对象网关”。例如,如果我们有 ,那么我们将有一个 人物入口来存储域对象 Person 到数据库。如果我们有 Person、 Employee、 Customer 等,我们将有 PersonGateway、 EmployeeGateway 和 CustomerGateway。每个网关将有特定的 CRUD 功能的对象,它与其他网关没有任何关系。这里没有可重用的代码/模块。网关可以进一步划分为 RowDataGateway 或 TableGateway,这取决于传递的是“ id”还是“ object”。网关通常与活动记录进行比较。它将域模型与数据库模式绑定在一起。

    Repository/DataMapper/DAO : 它们是一回事。它们都引用将数据库实体传输到域模型的持久层。与网关不同,Repository/DataMapper/DAO 隐藏实现。你不知道 Person 后面是否有 PersonGateway。也许会,也许不会,你不在乎。您只知道它必须为每个域对象支持 CRUD 操作。它解耦了数据源和域模型。