Handelt es sich bei "Mapper" um ein gültiges Entwurfsmuster oder handelt es sich um eine Variation des "Factory" -Musters?

37

Ein verbreitetes Muster, das ich sehe, ist das sogenannte MapperMuster (nicht zu verwechseln mit DataMapperdem etwas ganz anderes ist), das als Argument eine Art "rohe" Datenquelle (z. B. ein ADO.NET DataReaderoder DataSet) verwendet und die Felder zuordnet Eigenschaften für ein Geschäfts- / Domänenobjekt. Beispiel:

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

Die Idee ist Ihr Gateway / DAO / Repository / etc. wird den Mapper aufrufen, bevor er zurückgegeben wird, sodass Sie ein umfangreiches Geschäftsobjekt im Vergleich zum zugrunde liegenden Datencontainer erhalten.

Dies scheint jedoch mit dem Factory-Muster (im DDD-Sprachgebrauch jedenfalls) zu tun zu haben, das ein Domänenobjekt erstellt und zurückgibt. Wikipedia sagt dies bezüglich der DDD Factory:

Factory: Methoden zum Erstellen von Domänenobjekten sollten an ein spezialisiertes Factory-Objekt delegiert werden, sodass alternative Implementierungen leicht ausgetauscht werden können.

Von diesem Zitat aus kann ich mir nur vorstellen, dass die DDD-ähnliche Factory so parametrisiert werden kann, dass sie bei Bedarf einen speziellen Objekttyp zurückgibt (z. B. BusinessCustomer oder ResidentialCustomer), während der "Mapper" einer bestimmten Klasse zugeordnet ist und nur tut Übersetzung.

Gibt es also einen Unterschied zwischen diesen beiden Mustern oder sind sie im Wesentlichen dasselbe mit unterschiedlichen Namen?

Wayne Molina
quelle
Unterscheidet sich dies von ORM und wenn ja, wo liegt der Unterschied?
JB King
ORMs übernehmen das Mapping automatisch für Sie - dies gilt eher für ein Szenario, in dem Sie kein ORM verwenden können (oder Ihre eigene Datenschicht / Thin-ORM schreiben müssen)
Wayne Molina,
1
Ich kämpfe wirklich darum zu sehen, wie DataMapper "etwas ganz anderes" ist.
pdr
Vielleicht irre ich mich - ich dachte, das DataMapperMuster hat den Datenbankzugriff selbst ausgeführt, während dieser "Mapper" nicht aus der Datenbank abruft, sondern nur eine Ergebnismenge in ein Objekt konvertiert.
Wayne Molina
martinfowler.com/eaaCatalog/dataMapper.html Ich verstehe irgendwie, was Sie meinen, aber wenn Sie diesen letzten Absatz lesen, ist es ungefähr richtig. Schauen Sie sich den PEAA-Katalog an. martinfowler.com/eaaCatalog/index.html . Was Sie beschreiben, ist sicherlich eine Art Mapper und passt besser zu DataMapper als der Rest.
pdr

Antworten:

23

Obwohl dies das erste Mal ist, dass ich von dem Mapper-Muster höre, klingt es für mich eher nach dem Builder-Muster als nach der Factory.

Im Factory-Muster kapseln Sie die Logik zum Erstellen von Objekten mehrerer zusammengehöriger Klassen. Das beste Beispiel wäre eine Situation, in der Sie in Abhängigkeit von bestimmten Parametern ein Objekt einer bestimmten Unterklasse einer abstrakten Basisklasse erstellen müssen. Eine Factory gibt also immer einen Zeiger oder eine Referenz auf die Basisklasse zurück, erstellt jedoch tatsächlich ein Objekt der entsprechenden abgeleiteten Klasse basierend auf den von Ihnen angegebenen Parametern.

Im Gegensatz dazu erstellt eine Builder-Klasse immer Objekte derselben Klasse. Sie würden es verwenden, wenn die Erstellung eines Objekts kompliziert ist, z. B. wenn der Konstruktor viele Argumente benötigt, von denen möglicherweise nicht alle sofort verfügbar sind. So kann ein Builder-Objekt ein Ort sein, an dem die Werte für die Konstruktorargumente gespeichert werden, bis Sie alle haben und bereit sind, das "Produkt" zu erstellen, oder es kann sinnvolle Standardwerte bereitstellen und Sie können nur die Argumente angeben, deren Werte Sie benötigen Veränderung. Ein typischer Anwendungsfall für das Builder-Muster ist das Erstellen von Objekten, die Sie möglicherweise in einem Komponententest benötigen, um eine Überfrachtung des Testcodes mit der gesamten Erstellungslogik zu vermeiden.

Für mich klingt ein Mapper wie eine Variante eines Builders, bei der die Konstruktorparameter in Form eines Datenbankdatensatzes oder einer anderen "Roh" -Datenstruktur vorliegen.

Dima
quelle
Hmm, ich hatte von Builder gehört, wusste aber nicht zu 100%, was es bedeutete - das half, die Dinge aufzuklären! Es hört sich fast so an, als ob der Hauptunterschied darin besteht, dass Factory eine Interface- / Abstract-Klasse zurückgibt, die wirklich eine konkrete Klasse ist, die auf Parametern basiert (sofern dies Sinn macht), während ein Builder / Mapper tatsächliche Daten aufnimmt und diese Eigenschaften ohne viel (falls überhaupt) Logik zuordnet ?
Wayne Molina
1
@Waine M: so ziemlich. In einem Builder kann zwar viel Logik stecken, da die Zuordnung von Daten zu Eigenschaften möglicherweise gar nicht so einfach ist. Tatsächlich kann ein Builder andere Builder zum Erstellen der Parameter enthalten. :)
Dima
5
Mit dem Builder-Muster können Sie alle Informationen, die zum Erstellen eines komplexen (normalerweise unveränderlichen) Objekts im Laufe der Zeit erforderlich sind, einfügen und das Objekt am Ende des Prozesses instanziieren. Das ist nicht was hier passiert.
pdr
+1 Einverstanden, dass dies ein vernünftiger Ansatz ist, bei dem eine separate 'Mapper'-Klasse als Vermittler zwischen DTO-Objekten und Domänenmodellobjekten fungiert. Dies ist auch nützlich, wenn die Domänenmodellobjekte beim Erstellen in einen bestimmten Status versetzt werden müssen (z. B. die .NET ISupportInitialize-Schnittstelle).
MattDavey
@pdr, ich bin damit einverstanden, dass ein Mapper nicht genau wie ein Builder ist, da alle Daten auf einmal verfügbar sind. Aber es ist sehr ähnlich, weil es nur eine Art von Objekten erstellt.
Dima
8

Mapper, Builder und Factory haben nur gemeinsam, dass sie eine "konstruierte Produkt" - und Objektinstanz eines Typs liefern. Um jegliche Verwirrung zu vermeiden, verweise ich auf die folgenden Diskussionen bezüglich ihrer jeweiligen Definition.

  1. Mapper - in der Nähe dessen, was hier erklärt wird: http://www.codeproject.com/KB/library/AutoMapper.aspx . Dies ist nicht genau das gleiche wie oben - aber am nächsten fand ich über Mapper.

  2. Builder - wie hier definiert: http://www.oodesign.com/builder-pattern.html

  3. Factory - wird hier definiert: http://www.oodesign.com/factory-pattern.html

Der Mapper ist im Wesentlichen ein Inside-Out-Konstruktor. Nehmen wir für eine Weile an, Sie haben keinen Mapper. Wenn Sie dennoch viele Parameter benötigen, sind sie alle Argumente im Konstruktor. Jetzt, da sich die Dinge weiterentwickeln, sind einigen Anwendungen zusätzliche Attribute nicht bekannt, die in Konstruktoren abgelegt werden müssen, in denen sie entweder berechnet oder Standardwerte verwendet werden. Entscheidend ist, dass Mapper dies für Sie tun kann - und es wäre sinnvoller, wenn dies mit externen Objekten verknüpft wäre, um einen solchen Algorithmus für die Konstruktion zu bestimmen.

Der Builder unterscheidet sich stark von Mapper. Ein Builder ist wichtig, wenn ein vollständiges Objekt aus vielen Teilen des Objekts besteht. Es ist eine Art Zusammenbau der Objekte, indem viele Teile zusammengefügt werden. Sogar die Initialisierung der einzelnen Teilobjekte hängt mit der Existenz anderer Teile zusammen.

Das Fabrikmuster sieht von Anfang an sehr einfach aus. Es gibt ein neu erstelltes Objekt zurück. Kann mir ein gewöhnlicher Konstruktor mit einem Operator wie new () eine voll funktionsfähige Instanz geben? Warum brauche ich eine Fabrik, die die gleichen Ergebnisse liefert?

Die Verwendung des Factory-Musters ist jedoch in der Regel sehr spezifisch. obwohl meistens nicht in der Literatur angezeigt, wo dies angewendet wird. Normalerweise erstellt eine Anwendung eine Factory, die für verschiedene Objekte freigegeben wird, die während der Ausführung solche Produktobjekte erstellen müssen. Wenn viele solcher Produkte erstellt werden, können mit der Factory-Methode Objekte basierend auf bestimmten Richtlinien erstellt werden. Beispielsweise kann eine bestimmte Vorlage erzwungen werden, die von der Factory-Methode verwendet wird, wenn alle Objekte erstellt werden. Dies ist keine Buildermethode. hier ist das Produkt nur eins (und unabhängig). Dies ist auch nicht wie Mapper; Hier ist der externe Datensatz zum Erstellen eines Objekts gemäß dem Client tatsächlich minimal. Das Fabrikmuster liefert wirklich (wie der Name schon sagt) durchgehend ähnliche Produktobjekte!

Dipan.

Dipan Mehta
quelle
4

Wenn ich mir die Antworten ansehe, sehe ich, dass alle Befragten semantisch falsche Antworten geben. Ich denke, das liegt daran, dass Sie sich nur allzu sehr auf die Frage konzentrieren, wie Mapper mit Factory oder Builder zusammenhängt.

In der Tat ist Mapper NICHT mit einer Fabrik oder einem Bauunternehmer verwandt. Mapper ähnelt am ehesten dem Adaptermuster (unter Verwendung der GoF-Sprache). Das Adaptermuster bietet Funktionen zum Konvertieren einer Darstellung in eine andere. Das OP verwies auf das DataSet und den DataReader in ADO.NET - und wie steht es mit dem SqlDataAdapter? Die Antwort liegt im Namen. Mapper ist ein neuer Name für etwas, von dem ältere Programmierer schon lange wissen: Adapter.

Mapper konvertiert eine Darstellung in eine andere - genau die Definition des Adaptermusters.

Reuben Soto
quelle
1

Was Sie hier tun, ist tatsächlich eine Art Typkonvertierung (Sie konvertieren Ihre Rohdaten in ein Geschäftsobjekt). Sie können das Factory-Muster verwenden, um genau das zu tun (dh, Konvertierungen). In gewisser Weise ist Ihre Klasse also eine Factory (obwohl ich dafür eine statische Factory verwenden würde ).

Oliver Weiler
quelle
0

Builder kapseln komplexe Geschäftslogik, um ein Objekt zu erstellen. Mapper hingegen sollte nur die Felder von einem zum anderen kopieren.

Beispiel: Zuordnung von Datenbank-Mitarbeiterobjekt zu Domänen-Mitarbeiterobjekt, Zuordnung von Domänen-Mitarbeiterobjekt zu Kundenvertrag.

Builder hosten dagegen mehrere Geschäftsentscheidungen, um ein Objekt zu erstellen . Aus Sicht der Einzelverantwortung ist dies sinnvoll.

user95940
quelle