“映射程序”是有效的设计模式还是“工厂”模式的变体?


37

我看到的一个常见模式就是所谓的Mapper模式(不要与之DataMapper完全混淆),它以某种“原始”数据源(例如ADO.NET DataReaderDataSet)作为参数,并将字段映射到业务/域对象上的属性。例:

class PersonMapper
{
    public Person Map(DataSet ds)
    {
        Person p = new Person();
        p.FirstName = ds.Tables[0].Rows[0]["FirstName"].ToString();
        // other properties...
        return p;
    }
}

这个想法是您的Gateway / DAO / Repository / etc。将在Mapper返回之前调用它,因此您将获得一个丰富的业务对象与基础数据容器。

但是,这似乎与工厂模式有关(即使不完全相同),工厂模式会构造并返回域对象。维基百科说这是:DDD工厂:

工厂:用于创建域对象的方法应委托给专门的工厂对象,以便可以轻松地互换替代实现。

从该引用中,我唯一想到的区别是可以对DDD样式的工厂进行参数化,以便在需要将“映射器”键入特定类的情况下,如果需要的话可以返回一种特殊类型的对象(例如BusinessCustomer与ResidentialCustomer)。并且翻译。

那么这两种模式之间是否存在差异,或者它们本质上是相同的东西却具有不同的名称?


这与ORM有区别吗?如果有,区别在哪里?
JB King

ORM会自动为您处理映射-对于无法使用ORM(或必须编写自己的数据层/薄ORM)的情况,这更有用
Wayne Molina

1
我真的很努力地了解DataMapper如何“完全替代”。
pdr

也许我弄错了-我以为DataMapper模式是数据库自己访问的,而这个“映射器”不是从数据库中提取的,只是将某种结果集转换为对象。
韦恩·莫利纳

martinfowler.com/eaaCatalog/dataMapper.html我有点明白您的意思了,但是,阅读最后一段,那是正确的。查看PEAA目录。martinfowler.com/eaaCatalog/index.html。您所描述的肯定是Mapper的一种,并且比其余的更适合DataMapper。
pdr

Answers:


23

尽管这是我第一次听说Mapper模式,但对我来说听起来更像是Builder模式,而不是Factory。

在Factory模式中,您封装了用于创建多个相关类的对象的逻辑。最主要的例子是您需要根据某些参数创建某个抽象基类的特定子类的对象的情况。因此,Factory总是返回指向基类的指针或引用,但实际上它会根据您提供的参数创建适当的派生类的对象。

相反,Builder类始终创建相同类的对象。如果对象的创建很复杂,则可以使用它,例如,其构造函数需要很多参数,但并非所有参数都可以立即使用。因此,构建器对象可能是一个存储构造函数参数值的位置,直到您拥有所有值并准备创建“产品”为止,或者它可以提供合理的默认值,并仅允许您指定需要其值的参数。更改。Builder模式的一个典型用例是创建单元测试中可能需要的对象,以避免所有创建逻辑造成测试代码混乱。

对我来说,Mapper听起来像是Builder的一种变体,其中构造函数参数以数据库记录或其他“原始”数据结构的形式出现。


嗯,我听说过Builder,但是并没有100%意识到它所包含的内容-这有助于清除一切!几乎听起来像是主要的区别是Factory返回了一个接口/抽象类,它实际上是一个基于参数的具体类(如果有意义),而Builder / Mapper则采用实际数据并将其映射到属性,而没有太多(如果有)逻辑?
韦恩·莫利纳

1
@Waine M:差不多。尽管在Builder中可能有很多逻辑,但是由于数据到属性的映射可能根本不是直截了当的。实际上,一个构建器可能包含其他构建器来构建参数。:)
Dima

5
Builder模式允许您随着时间的推移放置构建复杂(通常是不可变的)对象所需的所有信息,然后在流程结束时实例化该对象。这不是这里发生的事情。
pdr

+1同意这是一种明智的方法,拥有一个单独的“映射器”类来充当DTO对象和域模型对象之间的中介。当域模型对象在构造时需要置于某种特殊状态(即.NET ISupportInitialize接口)时,它也很方便。
MattDavey 2011年

@pdr,我同意Mapper与构建器并不完全一样,因为所有数据都可以一次获得。但这非常相似,因为它仅构建一种类型的对象。
迪马

8

关于Mapper,Builder和Factory的唯一共同之处是它们提供了“构造产品”和类型的对象实例。为避免混淆,我将参考以下讨论分别定义。

  1. 映射器-接近此处解释的内容:http : //www.codeproject.com/KB/library/AutoMapper.aspx。这与上面的不完全相同-但我发现与mapper最接近。

  2. 生成器-此处定义:http//www.oodesign.com/builder-pattern.html

  3. 工厂-在此处定义:http : //www.oodesign.com/factory-pattern.html

映射器本质上是一个由内而外的构造函数。假设有一段时间,如果您没有映射器-无论何时您需要许多参数集,它们都是构造函数上的参数。现在随着事情的发展,一些应用程序不再意识到需要在构造函数下进行计算或使用默认属性的其他属性。至关重要的是,映射器可以为您完成此任务-如果它与外部对象链接以决定这种构造算法,则将更加有用。

生成器与映射器有很大不同。当使用对象的许多部分组成一个完整的对象时,构建器必不可少。这是通过将许多零件装配在一起来组装对象。甚至单个零件对象的初始化也与其他零件的存在有关。

一开始,工厂模式看起来非常简单。它返回一个新构造的对象。是否有任何普通的构造函数可以使用new()这样的运算符为我提供功能齐全的实例?为什么我需要一家能给我同样结果的工厂?

但是,工厂模式的用法通常非常具体。尽管大多数情况下,未在使用此方法的文献中显示。通常,应用程序创建一个工厂,该工厂与执行过程中需要创建此类产品对象的各种对象共享。当创建许多此类产品时,Factory方法允许基于某种策略创建对象,例如,当创建所有对象时,可以强制使用某种特定的模板,该模板由Factory方法使用。这既不是构建器方法,也不是构建器方法。这里的产品出来的只是一个(而且是独立的)。这也不像映射器。在这里,根据客户端创建对象的外部数据集实际上是最少的。工厂模式确实提供(顾名思义)一致的相似产品对象!

地盘



4

当我查看答案时,我看到受访者都提供了语义上不正确的答案。我认为这是因为您太关注这个问题了,这个问题关注的是mapper与工厂或建筑商的关系。

实际上,Mapper不类似于工厂或制造商。映射器最类似于适配器模式(使用GoF说法)。适配器模式提供了将一种表示形式转换为另一种表示形式的功能。OP在ADO.NET中引用了DataSet和DataReader -那么SqlDataAdapter怎么样?答案就是名字。较早的程序员早就知道的东西Mapper是一个新名称:适配器。

映射器将一种表示形式转换为另一种形式-适配器模式的定义。


1

您在这里所做的实际上是某种类型转换(您将原始数据转换为业务对象)。您可以使用Factory模式精确地执行此操作(即,类型转换),所以,以某种方式,您的类是工厂(尽管我会为此使用静态工厂)。


0

构建器封装复杂的业务逻辑以构建对象。另一方面,Mapper应该将字段从一个字段复制到另一个字段。

例如,从数据库雇员对象映射到域雇员对象,从域雇员对象映射到客户合同。

另一方面,构建器负责多个业务决策以构建对象。从单一职责的角度来看,这是有道理的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.