Est-ce que “Mapper” est un motif valide ou est-ce une variante du motif “Usine”?

37

Un modèle courant que je vois est ce qu’on appelle le Mappermodèle (à ne pas confondre avec DataMapperce qui est autre chose), qui prend comme argument une sorte de source de données "brute" (par exemple un ADO.NET DataReaderou DataSet) et mappe les champs sur propriétés sur un objet métier / domaine. Exemple:

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

L'idée étant votre passerelle / DAO / référentiel / etc. appelle dans le mappeur avant son retour, vous obtenez donc un objet métier riche par rapport au conteneur de données sous-jacent.

Cependant, cela semble être lié, sinon identique, au modèle Factory (de toute façon dans le langage DDD), qui construit et retourne un objet de domaine. Wikipedia dit ceci: l'usine DDD:

Factory: les méthodes de création d'objets de domaine doivent être déléguées à un objet Factory spécialisé, de sorte que les implémentations alternatives puissent être facilement échangées.

À partir de cette citation, la seule différence à laquelle je pouvais penser est que l’usine de style DDD puisse être paramétrée de manière à renvoyer un type d’objet spécialisé si le besoin s’en faisait sentir (par exemple, BusinessCustomer contre ResidentialCustomer) alors que le "Mappeur" était associé à une classe spécifique. et seulement la traduction.

Y a-t-il une différence entre ces deux modèles ou s'agit-il essentiellement de la même chose avec des noms différents?

Wayne Molina
la source
Est-ce différent de ORM et si oui, où est la différence?
JB King
Les ORM gèrent automatiquement le mappage pour vous - il s'agit davantage d'un scénario dans lequel vous ne pouvez pas utiliser d'ORM (ou devez écrire votre propre couche de données / ORM mince)
Wayne Molina
1
J'ai vraiment du mal à comprendre en quoi DataMapper est "tout à fait autre chose".
pdr
Peut-être que je me trompe - je pensais que le DataMappermodèle d'accès à la base de données lui-même était accessible, alors que ce "mappeur" ne extrait pas de la base de données, mais convertit simplement un ensemble de résultats en un objet.
Wayne Molina
martinfowler.com/eaaCatalog/dataMapper.html Je vois un peu ce que vous voulez dire mais, en lisant ce dernier paragraphe, c'est à peu près correct. Regardez le catalogue PEAA. martinfowler.com/eaaCatalog/index.html . Ce que vous décrivez est certainement un type de mappeur et correspond mieux au DataMapper que le reste.
pdr

Réponses:

23

Même si c’est la première fois que j’entends parler du motif Mapper, cela ressemble plus au motif Builder qu’à la Factory.

Dans le modèle Factory, vous encapsulez la logique permettant de créer des objets d'un certain nombre de classes liées. Le premier exemple serait une situation dans laquelle vous devez créer un objet d'une sous-classe particulière d'une classe de base abstraite en fonction de certains paramètres. Ainsi, une fabrique renvoie toujours un pointeur ou une référence à la classe de base, mais crée en fait un objet de la classe dérivée appropriée en fonction des paramètres que vous lui spécifiez.

En revanche, une classe Builder crée toujours des objets de la même classe. Vous l'utiliserez si la création d'un objet est compliquée. Par exemple, son constructeur prend beaucoup d'arguments, qui ne sont pas tous disponibles instantanément. Ainsi, un objet générateur peut être un emplacement qui stocke les valeurs des arguments du constructeur jusqu'à ce que vous les ayez tous et prêt à créer le "produit", ou il peut fournir des valeurs par défaut raisonnables et vous permettre de spécifier uniquement les arguments dont vous avez besoin changement. Un exemple typique d'utilisation du modèle de générateur est la création d'objets dont vous pourriez avoir besoin dans un test unitaire, afin d'éviter d'encombrer le code de test avec toute la logique de création.

Pour moi, un mappeur ressemble à une variante d'un constructeur, où les paramètres du constructeur se présentent sous la forme d'un enregistrement de base de données ou d'une autre structure de données "brute".

Dima
la source
Hmm, j'avais entendu parler de Builder mais je n'étais pas à 100% conscient de ce que cela impliquait - cela a aidé à clarifier les choses! On dirait presque que la différence majeure est que Factory retourne une classe abstraite / interface qui est vraiment une classe concrète basée sur des paramètres (si cela a du sens), tandis qu'un générateur / mappeur prend les données réelles et les mappe vers des propriétés, sans beaucoup de logique (le cas échéant). ?
Wayne Molina
1
@Waine M: à peu près. Bien qu'il puisse y avoir beaucoup de logique dans un générateur, le mappage des données sur les propriétés peut ne pas être simple. En fait, un générateur peut contenir d'autres générateurs pour générer les paramètres. :)
Dima
5
Le modèle de générateur vous permet de mettre toutes les informations requises pour construire un objet complexe (généralement immuable) dans le temps, puis d'instancier l'objet à la fin du processus. Ce n'est pas ce qui se passe ici.
pdr
+1 Il a été convenu qu'il s'agissait d'une approche judicieuse, ayant une classe 'mappeur' distincte servant de médiateur entre les objets DTO et les objets de modèle de domaine. Il est également utile lorsque les objets du modèle de domaine doivent être placés dans un état spécial lors de leur construction (c'est-à-dire l'interface .NET ISupportInitialize).
MattDavey
@pdr, je conviens qu'un mappeur n'est pas exactement un constructeur, car toutes les données sont disponibles en même temps. Mais il est très similaire, car il ne construit qu'un seul type d'objets.
Dima
8

La seule chose commune à propos de Mapper, Builder et Factory, c'est qu'ils fournissent un "produit construit" - et une instance d'objet d'un type. Pour éviter toute confusion, je me réfère aux discussions suivantes pour leur définition respective.

  1. Mappeur - proche de ce qui est expliqué ici: http://www.codeproject.com/KB/library/AutoMapper.aspx . Ce n'est pas exactement la même chose que ci-dessus - mais j'ai trouvé le mappeur le plus proche.

  2. Constructeur - tel que défini ici: http://www.oodesign.com/builder-pattern.html

  3. Factory - est défini ici: http://www.oodesign.com/factory-pattern.html

Le mappeur est essentiellement un constructeur. Supposons un instant que vous n'ayez pas de mappeur - Lorsque vous avez de toute façon besoin de plusieurs jeux de paramètres, ils sont tous des arguments du constructeur. Au fur et à mesure que les choses évoluent, certaines applications ne sont pas conscientes des attributs supplémentaires qui doivent passer sous le constructeur, où ils sont calculés ou utilisent les valeurs par défaut. L'essentiel est que le mappeur puisse le faire pour vous - et qu'il serait plus utile s'il existe un lien avec des objets externes pour décider d'un tel algorithme pour la construction.

Le constructeur est très différent du mappeur. Un générateur est essentiel lorsqu'un objet complet est composé à l'aide de plusieurs parties de l'objet. C'est un peu comme assembler les objets en assemblant plusieurs pièces. Même l'initialisation des objets de pièce individuels est liée à l'existence d'autres pièces.

Les modèles d'usine semblent très simples au début. Il retourne des objets nouvellement construits. Si un constructeur ordinaire peut me donner une instance entièrement fonctionnelle en utilisant un opérateur comme new ()? Pourquoi aurais-je besoin d'une usine qui me donne les mêmes résultats?

Cependant, l'utilisation du modèle d'usine est généralement très spécifique; bien que le plus souvent, n'apparaisse pas dans la littérature où cela est appliqué. Généralement, une application crée une fabrique qui est partagée avec divers objets qui doivent créer de tels objets de produit lors de l'exécution. Lorsque de nombreux produits de ce type sont créés, la méthode Factory permet de créer des objets en fonction de certaines règles. Par exemple, il est possible de forcer un certain modèle utilisé par la méthode Factory lorsque tous les objets sont créés. Ce n'est ni comme une méthode de construction; ici le produit est unique (et indépendant). Ce n'est pas non plus comme mappeur; Ici, le jeu de données externe permettant de créer un objet selon le client est en réalité minimal. Le modèle d'usine fournit (comme son nom l'indique) des objets produits toujours similaires!

Dipan.

Dipan Mehta
la source
4

En parcourant les réponses, je constate que les répondants fournissent tous des réponses sémantiquement incorrectes. Je pense que c’est parce que vous êtes tous trop concentrés sur la question, qui est axée sur la relation entre le mappeur et l’usine ou le constructeur.

Quand en fait, Mapper ne ressemble pas à une usine ou à un constructeur. Le mappeur ressemble plus au modèle d' adaptateur (utilisant le langage GoF). Le modèle d'adaptateur fournit une fonctionnalité permettant de convertir une représentation en une autre. Le PO faisait référence au DataSet et au DataReader dans ADO.NET - que diriez-vous du SqlDataAdapter? La réponse est dans le nom. Mapper est un nouveau nom pour quelque chose que les programmeurs plus anciens connaissent depuis longtemps: les adaptateurs.

Mapper convertit une représentation en une autre - la définition même du modèle d'adaptateur.

Reuben Soto
la source
1

Ce que vous faites ici est en réalité une sorte de conversion de type (vous convertissez vos données brutes en un objet métier). Vous pouvez utiliser le modèle d'usine pour faire exactement cela (c.-à-d. Les conversions de types), alors oui, d'une manière ou d'une autre, votre classe est une usine (bien que j'utiliserais une usine statique pour cela).

Oliver Weiler
la source
0

Les générateurs encapsulent une logique métier complexe pour créer un objet. Mapper, d'autre part, devrait simplement copier les champs de l'un à l'autre.

Par exemple, mapper d'un objet employé de base de données à un objet employé du domaine, mapper d'un objet employé du domaine à un contrat client.

Les constructeurs, quant à eux, hébergent plusieurs décisions commerciales pour créer un objet. Du point de vue de la responsabilité unique, cela a du sens.

utilisateur95940
la source