O “Mapper” é um padrão de design válido ou é uma variação do padrão “Factory”?


37

Um padrão comum que vejo é o que é conhecido como Mapperpadrão (que não deve ser confundido com o DataMapperque é algo totalmente diferente), que usa como argumento algum tipo de fonte de dados "bruta" (por exemplo, um ADO.NET DataReaderou DataSet) e mapeia os campos para propriedades em um objeto de negócios / domínio. Exemplo:

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

A ideia é o seu Gateway / DAO / Repositório / etc. chamará o Mapper antes de retornar, para que você obtenha um objeto de negócios rico versus o contêiner de dados subjacente.

No entanto, isso parece estar relacionado, se não idêntico, ao padrão Factory (na linguagem DDD, de qualquer maneira), que constrói e retorna um objeto de domínio. A Wikipedia diz o seguinte: a fábrica DDD:

Factory: os métodos para criar objetos de domínio devem delegar para um objeto Factory especializado, de modo que implementações alternativas possam ser facilmente trocadas.

A partir dessa citação, a única diferença que pude pensar é que a Fábrica no estilo DDD pode ser parametrizada para retornar um tipo especializado de objeto, se surgir a necessidade (por exemplo, BusinessCustomer versus ResidentialCustomer) enquanto o "Mapper" estiver ligado a uma classe específica e apenas faz tradução.

Então, existe uma diferença entre esses dois padrões ou eles são essencialmente a mesma coisa com nomes diferentes?


Isso é diferente do ORM e, em caso afirmativo, qual é a diferença?
JB King #

ORMs lidar com o mapeamento automaticamente para você - isso é mais para um cenário onde você não pode usar um ORM (ou tem que escrever a sua camada de dados próprio ORM / fina)
Wayne Molina

11
Estou realmente lutando para ver como o DataMapper é "algo completamente diferente".
PDR

Talvez eu esteja enganado - eu pensei que o DataMapperpadrão acessou o banco de dados, enquanto esse "Mapper" não é extraído do banco de dados, apenas converte um conjunto de resultados de algum tipo em um objeto.
Wayne Molina

martinfowler.com/eaaCatalog/dataMapper.html Eu meio que entendo o que você quer dizer, mas, lendo o último parágrafo, está certo. Veja o catálogo PEAA. martinfowler.com/eaaCatalog/index.html . O que você está descrevendo é certamente um tipo de mapeador e se encaixa melhor ao DataMapper do que o resto.
PDR

Respostas:


23

Embora seja a primeira vez que ouço o padrão Mapper, para mim, parece mais o padrão Builder do que o Factory.

No padrão de fábrica, você encapsula a lógica para criar objetos de várias classes relacionadas. O exemplo principal seria uma situação em que você precisa criar um objeto de uma subclasse específica de alguma classe base abstrata, dependendo de alguns parâmetros. Portanto, um Factory sempre retorna um ponteiro ou uma referência à classe base, mas na verdade cria um objeto da classe derivada apropriada com base nos parâmetros que você fornece.

Por outro lado, uma classe Builder sempre cria objetos da mesma classe. Você o usaria se a criação de um objeto fosse complicada, por exemplo, seu construtor usa muitos argumentos, nem todos disponíveis instantaneamente. Portanto, um objeto construtor pode ser um local que armazena os valores para os argumentos do construtor até você ter todos eles e estar pronto para criar o "produto", ou pode fornecer valores padrão razoáveis ​​e permitir especificar apenas os argumentos cujos valores você precisa mudança. Um caso de uso típico para o padrão Builder é para criar objetos que você pode precisar em um teste de unidade, para evitar sobrecarregar o código de teste com toda a lógica de criação.

Para mim, um mapeador soa como uma variante de um construtor, onde os parâmetros do construtor vêm na forma de um registro de banco de dados ou alguma outra estrutura de dados "bruta".


Hmm, eu tinha ouvido falar do Builder, mas não estava 100% ciente do que isso implicava - isso ajudou a esclarecer as coisas! Quase parece que a principal diferença é que o Factory retorna uma interface / classe abstrata que é realmente uma classe concreta com base em parâmetros (se isso fez sentido) enquanto um Construtor / Mapeador pega dados reais e os mapeia para propriedades, sem muita (se houver) lógica ?
Wayne Molina

11
@ WAine M: praticamente. Embora possa haver muita lógica em um Construtor, porque o mapeamento de dados para propriedades pode não ser direto. De fato, um construtor pode conter outros construtores para construir os parâmetros. :)
Dima

5
O padrão Builder permite que você coloque todas as informações necessárias para criar um objeto complexo (geralmente imutável) ao longo do tempo e instancie o objeto no final do processo. Não é o que está acontecendo aqui.
PDR

+1 Concordou que essa é uma abordagem sensata, com uma classe 'mapper' separada para atuar como mediadora entre objetos DTO e objetos de modelo de domínio. Também é útil quando os objetos de modelo de domínio precisam ser colocados em algum estado especial ao serem construídos (por exemplo, interface .NET ISupportInitialize).
precisa saber é o seguinte

@pdr, eu concordo que um mapeador não é exatamente como um construtor, porque todos os dados estão disponíveis ao mesmo tempo. Mas é muito semelhante, porque cria apenas um tipo de objetos.
Dima

8

A única coisa comum sobre o Mapper, Builder e Factory é que eles entregam um "produto construído" - e uma instância de objeto de um tipo. Para evitar qualquer confusão, refiro-me às discussões a seguir para sua respectiva definição.

  1. Mapeador - próximo ao explicado aqui: http://www.codeproject.com/KB/library/AutoMapper.aspx . Isso não é exatamente o mesmo que acima - mas o mais próximo que encontrei sobre o mapper.

  2. Construtor - conforme definido aqui: http://www.oodesign.com/builder-pattern.html

  3. Fábrica - é definida aqui: http://www.oodesign.com/factory-pattern.html

O mapeador é essencialmente um construtor de dentro para fora. Suponha por um tempo, se você não tiver um mapeador - quando você precisar de muitos conjuntos de parâmetros, todos serão argumentos no construtor. Agora, à medida que as coisas evoluem, alguns aplicativos não estão cientes de atributos adicionais que precisam ser construídos no local em que alguém o calcula ou usa o padrão. O ponto crítico é que o mapeador pode fazer isso por você - e seria mais útil se isso tivesse ligação com objetos externos para decidir esse algoritmo para construção.

O Builder é muito diferente do mapeador. Um construtor é essencial quando um objeto completo é composto usando várias partes do objeto. É como montar os objetos, encaixando muitas partes. Até a inicialização dos objetos individuais da parte está relacionada à existência de outras partes.

Os padrões de fábrica parecem muito simples desde o início. Retorna objetos recém-construídos. Se algum construtor comum puder me fornecer uma instância totalmente funcional usando um operador como new ()? por que eu precisaria de uma fábrica que me desse os mesmos resultados?

No entanto, o uso do padrão de fábrica é geralmente muito específico; embora na maioria das vezes, não seja exibido na literatura onde isso é aplicado. Geralmente, um aplicativo cria uma fábrica que é compartilhada com vários objetos que precisam criar esses objetos de produto durante a execução. Quando muitos desses produtos são criados, o método Factory permite a criação de objetos com base em determinadas políticas, por exemplo, é possível forçar um determinado modelo que é usado pelo método factory quando todos os objetos são criados. Isso não é como um método construtor; aqui o produto fora é apenas um (e independente). Isso também não é como o mapeador; aqui, o conjunto de dados externos para criar objetos de acordo com o cliente é realmente mínimo. O padrão de fábrica realmente fornece (como o nome sugere) objetos de produto consistentemente semelhantes!

Dipan.



4

Ao examinar as respostas, vejo todos os respondentes fornecendo respostas semanticamente incorretas. Eu acho que isso ocorre porque você está muito focado na questão, que está focada em como o mapeador está relacionado à fábrica ou construtor.

Quando, de fato, o Mapper NÃO é semelhante à fábrica ou construtor. O Mapper é mais parecido com o padrão do adaptador (usando a linguagem GoF). O padrão do adaptador fornece funcionalidade para converter uma representação em outra. O OP se referiu ao DataSet e ao DataReader no ADO.NET - e quanto ao SqlDataAdapter? A resposta está no nome. Mapper é um novo nome para algo que os programadores mais antigos conhecem há muito tempo: adaptadores.

O Mapper converte uma representação em outra - a própria definição do padrão do adaptador.


1

O que você está fazendo aqui é na verdade algum tipo de conversão de tipo (você converte seus dados brutos em um objeto de negócios). Você pode usar o padrão de fábrica para fazer exatamente isso (ou seja, conversões de tipo), então sim, de alguma forma, sua classe é uma fábrica (embora eu usaria uma fábrica estática para isso).


0

Os construtores encapsulam uma lógica de negócios complexa para construir um objeto. Por outro lado, o mapeador deve copiar os campos de um para o outro.

Por exemplo, mapear do objeto Employee do banco de dados para o objeto Employee do domínio, mapear do objeto Employee do domínio para o contrato do cliente.

Os construtores, por outro lado, hospedam várias decisões de negócios para construir um objeto. Do ponto de vista de responsabilidade única, isso faz sentido.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.