¿Es "Mapper" un patrón de diseño válido o es una variación del patrón "Factory"?

37

Un patrón común que veo es lo que se conoce como el Mapperpatrón (que no debe confundirse con el DataMapperque es algo completamente diferente), que toma como argumento algún tipo de fuente de datos "en bruto" (por ejemplo, un ADO.NET DataReadero DataSet) y asigna los campos a propiedades en un objeto de negocio / dominio. Ejemplo:

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

La idea es su Gateway / DAO / Repository / etc. llamará al Mapper antes de que regrese, para que obtenga un objeto comercial rico en comparación con el contenedor de datos subyacente.

Sin embargo, esto parece estar relacionado, si no es idéntico, con el patrón Factory (en el lenguaje DDD, de todos modos), que construye y devuelve un objeto de dominio. Wikipedia dice esto re: la fábrica DDD:

Factory: los métodos para crear objetos de dominio deben delegar a un objeto Factory especializado de manera que las implementaciones alternativas puedan intercambiarse fácilmente.

A partir de esa cita, la única diferencia en la que puedo pensar es que la Fábrica de estilo DDD podría parametrizarse para que pudiera devolver un tipo de objeto especializado si fuera necesario (por ejemplo, BusinessCustomer versus ResidentialCustomer) mientras el "Mapper" está codificado para una clase específica y solo hace traducción.

Entonces, ¿hay alguna diferencia entre estos dos patrones o son esencialmente lo mismo con diferentes nombres?

Wayne Molina
fuente
¿Es esto diferente de ORM y, de ser así, dónde está la diferencia?
JB King
Los ORM manejan el mapeo automáticamente por usted: esto es más para un escenario en el que no puede usar un ORM (o tiene que escribir su propia capa de datos / ORM delgado)
Wayne Molina
1
Realmente estoy luchando por ver cómo DataMapper es "algo completamente diferente".
pdr
Tal vez me equivoque: pensé que el DataMapperpatrón accedía a la base de datos, mientras que este "Mapper" no se extrae de la base de datos, solo convierte un conjunto de resultados de algún tipo en un objeto.
Wayne Molina
martinfowler.com/eaaCatalog/dataMapper.html Más o menos entiendo a qué te refieres, pero al leer el último párrafo, es correcto. Mira el Catálogo PEAA. martinfowler.com/eaaCatalog/index.html . Lo que está describiendo es ciertamente un tipo de Mapper, y se ajusta más a DataMapper que el resto.
pdr

Respuestas:

23

Aunque esta es la primera vez que escucho sobre el patrón Mapper, para mí suena más como el patrón Builder que como Factory.

En el patrón Factory encapsula la lógica para crear objetos de varias clases relacionadas. El primer ejemplo sería una situación en la que necesita crear un objeto de una subclase particular de alguna clase base abstracta dependiendo de algunos parámetros. Por lo tanto, una Fábrica siempre devuelve un puntero o una referencia a la clase base, pero en realidad crea un objeto de la clase derivada adecuada en función de los parámetros que le proporcione.

Por el contrario, una clase Builder siempre crea objetos de la misma clase. Lo usaría si la creación de un objeto es complicada, por ejemplo, su constructor toma muchos argumentos, y no todos pueden estar disponibles al instante. Por lo tanto, un objeto generador podría ser un lugar que almacena los valores para los argumentos del constructor hasta que los tenga todos y esté listo para crear el "producto", o puede proporcionar valores predeterminados razonables y permitirle especificar solo los argumentos cuyos valores necesita cambio. Un caso de uso típico para el patrón Builder es crear objetos que pueda necesitar en una prueba unitaria, para evitar saturar el código de prueba con toda la lógica de creación.

Para mí, un Mapper suena como una variante de un Builder, donde los parámetros del constructor vienen en forma de un registro de base de datos o alguna otra estructura de datos "en bruto".

Dima
fuente
Hmm, había oído hablar de Builder, pero no estaba al 100% consciente de lo que implicaba, ¡esto ayudó a aclarar las cosas! Casi parece que la principal diferencia es que Factory devuelve una clase de interfaz / resumen que es realmente una clase concreta basada en parámetros (si eso tiene sentido), mientras que un Builder / Mapper toma datos reales y los asigna a propiedades, sin mucha lógica (si es que la hay) ?
Wayne Molina
1
@Waine M: más o menos. Aunque puede haber mucha lógica en un Builder, porque la asignación de datos a propiedades puede no ser del todo sencilla. De hecho, un constructor puede contener otros constructores para construir los parámetros. :)
Dima
55
El patrón Builder le permite poner toda la información requerida para construir un objeto complejo (generalmente inmutable) a lo largo del tiempo y luego crear una instancia del objeto al final del proceso. Eso no es lo que está pasando aquí.
pdr
+1 Convino en que este es un enfoque sensato, que tiene una clase separada de 'mapeador' para actuar como mediador entre los objetos DTO y los objetos del modelo de dominio. También resulta útil cuando los objetos del modelo de dominio deben ponerse en algún estado especial cuando se construyen (es decir, la interfaz .NET ISupportInitialize).
MattDavey
@pdr, estoy de acuerdo en que un Mapper no es exactamente como un generador, porque todos los datos están disponibles a la vez. Pero es muy similar, porque construye solo un tipo de objetos.
Dima
8

Lo único común sobre Mapper, Builder y Factory es que entregan un "producto construido" y una instancia de objeto de un tipo. Para evitar cualquier confusión, me refiero a las siguientes discusiones para su respectiva definición.

  1. Mapper: cerca de lo que se explica aquí: http://www.codeproject.com/KB/library/AutoMapper.aspx . Esto no es exactamente lo mismo que el anterior, pero lo más cercano que encontré sobre mapper.

  2. Constructor - como se define aquí: http://www.oodesign.com/builder-pattern.html

  3. Fábrica: se define aquí: http://www.oodesign.com/factory-pattern.html

El mapeador es esencialmente un constructor de adentro hacia afuera. Suponga por un tiempo, si no tiene un mapeador: cuando de todos modos necesita muchos conjuntos de parámetros, todos son argumentos sobre el constructor. Ahora, a medida que las cosas evolucionan, algunas aplicaciones no son conscientes de los atributos adicionales que deben ir debajo del constructor donde uno lo calcula o usa el valor predeterminado. Lo crítico es que el mapeador puede hacer esto por usted, y sería más útil si esto tiene un vínculo con objetos externos para decidir dicho algoritmo para la construcción.

El generador es muy diferente del mapeador. Un constructor es esencial cuando un objeto completo se compone usando muchas partes del objeto. Es como ensamblar los objetos al unir muchas partes. Incluso la inicialización de los objetos de parte individual está relacionada con la existencia de otras partes.

Los patrones de fábrica parecen muy simples desde el principio. Devuelve objetos recién construidos. ¿Si algún constructor ordinario me puede dar una instancia completamente funcional usando un operador como new ()? ¿Por qué necesitaría una fábrica que me dé los mismos resultados?

Sin embargo, el uso del patrón de fábrica suele ser muy específico; aunque con mayor frecuencia, no se muestra en la literatura donde se aplica esto. Por lo general, una aplicación crea una fábrica que se comparte con varios objetos que necesitan crear dichos objetos de producto durante la ejecución. Cuando se crean muchos de estos productos, el método Factory permite la creación de objetos basados ​​en cierta política, por ejemplo, se puede forzar una plantilla determinada que se utiliza con el método factory cuando se crean todos los objetos. Esto no es como un método de construcción; Aquí el producto es solo uno (e independiente). Esto tampoco es como el mapeador; aquí el conjunto de datos externos para crear objetos según el cliente es realmente mínimo. ¡El patrón de fábrica realmente proporciona (como su nombre lo indica) un objeto de producto consistentemente similar!

Dipan

Dipan Mehta
fuente
4

Cuando miro las respuestas, veo que todos los encuestados proporcionan respuestas semánticamente incorrectas. Creo que esto se debe a que está demasiado concentrado en la pregunta, que se centra en cómo se relaciona el mapeador con la fábrica o el constructor.

Cuando, de hecho, Mapper NO es similar a la fábrica o al constructor. Mapper se parece mucho al patrón adaptador (usando el lenguaje GoF). El patrón del adaptador proporciona funcionalidad para convertir una representación en otra. El OP se refirió al DataSet y al DataReader en ADO.NET, ¿qué tal el SqlDataAdapter? La respuesta está en el nombre. Mapper es un nuevo nombre para algo que los programadores más antiguos conocen desde hace mucho tiempo: los adaptadores.

Mapper convierte una representación en otra, la definición misma del patrón del adaptador.

Rubén Soto
fuente
1

Lo que está haciendo aquí es en realidad algún tipo de conversión de tipo (convierte sus datos sin procesar en un objeto comercial). Puede usar el patrón de fábrica para hacer exactamente eso (es decir, conversiones de tipo), así que sí, de alguna manera, su clase es una fábrica (aunque usaría una fábrica estática para eso).

Oliver Weiler
fuente
0

Los constructores encapsulan la lógica empresarial compleja para construir un objeto. Mapper, por otro lado, solo debe copiar los campos de uno a otro.

Por ejemplo, mapear del Objeto del Empleado de la Base de Datos al Objeto del Empleado del Dominio, mapear del Objeto del Empleado del Dominio al Contrato del Cliente.

Los constructores, por otro lado, alojan múltiples decisiones comerciales para construir un objeto. Desde el punto de vista de la responsabilidad única, esto tiene sentido.

usuario95940
fuente