Sollte die Parameterliste einer Methode Objekte oder Objektkennungen enthalten?

10

Unsere Teams führen folgende Diskussionen:

Angenommen, wir haben die folgenden zwei Methoden:

public Response Withdraw(int clubId, int terminalId,int cardId, string invoice, decimal amount);

public Response Withdraw(Club club, Terminal terminal,Card card, string invoice, decimal amount);

Was über das Kabel gesendet wird, sind nur die IDs.

Eine Seite sagt, dass die erste Methode richtig ist, weil wir nur die IDs von Terminal und Club haben und es klar sein sollte, dass wir nichts anderes haben, das ist mein Ansatz.

Die andere Seite sagt, dass die zweite Methode korrekt ist, weil sie flexibler ist.

Wir sind mit der Idee von Objektparametern vertraut, die andere Seite ist auch der Meinung, dass der Objektparameter die Objekte als Eigenschaften haben sollte.

Welches ist der richtige Ansatz?

Vielleicht gibt es einen dritten noch besseren Ansatz?

Mithir
quelle
Was? ...........
James
1
Kontext? Internetservice? WCF?
CodesInChaos
1
@ James - Entschuldigung, ich habe diese Frage ziemlich schnell geschrieben. Kannst du mir sagen, was nicht verstanden wird, damit ich sie bearbeiten kann?
Mithir
@CodesInChaos die Methoden sind eigentlich BL-Methoden
Mithir

Antworten:

10

Die Antwort ist kontextabhängig.

Wenn vom Client erwartet wird, dass alle diese Objekte bereits verfügbar sind , würde ich die Objektparameter verwenden. Andernfalls sieht ihr Code komplizierter aus, als er sein muss. (ZB haben sie Anrufe wie club.getId()zum Beispiel.)

Wenn dem Client nur die IDs leicht zur Verfügung stehen , ist der zweite Ansatz möglicherweise besser, da Sie möglicherweise nicht möchten, dass der Client alle diese Objekte zusammenstellen / laden muss, wenn Sie wirklich nur die IDs benötigen.

Eine Option besteht darin, beide Methoden bereitzustellen , damit der Client auswählen kann, welche verwendet werden soll (da dies Ihre API nicht überfüllt).

Im Allgemeinen sind die Objektparameter erweiterbarer, da Sie, wenn Sie in Zukunft ein anderes Datenelement für die Arbeit benötigen, keine andere Methode einführen müssen, die diese zusätzlichen Informationen verwendet.

Schließlich sollten Ihre Methodensignaturen nicht durch die Besonderheiten der Methode bestimmt werden (in Ihrem Fall, was genau über den Draht geht). Die API sollte abstrakt sinnvoll sein, damit Sie nicht geschraubt werden, wenn sich die Implementierung ändert.

c_maker
quelle
3
+1 Ich möchte nur noch einen Punkt hinzufügen: Bei Methoden, die remote aufgerufen werden ("over the wire"?), Kann das Übergeben von Objekten eine gründliche Serialisierung eines umfangreichen Objektbaums bedeuten. IDs sind ein hervorragender Ersatz für Objekte, wenn Sie sich Gedanken über die Größe einer Nutzlast für Remote-Anrufe machen.
Ross Patterson
1
In diesem Fall sieht es so aus, als wären Sie an eine Reihe von Abstraktionen gekoppelt, sodass das Übergeben von IDs Ihnen nicht mehr Flexibilität verschafft und wahrscheinlich die Wahrscheinlichkeit erhöht, dass Sie Parameter umkehren. Die Frage ist, wie eng der Code in der Methode mit den Abstraktionen gekoppelt ist, die ich übergebe. Zum Beispiel sollte eine Methode wie "validateCreditCard (Zeichenfolgekarte, Zeichenfolge cvi)" wahrscheinlich bei Grundelementen bleiben, um zu vermeiden, dass sie eng mit einer Art CreditCard-Objekt gekoppelt ist.
ipaul
Ich würde mich in der Mitte treffen und eine Schnittstelle in der Parameterliste verwenden. Dann kann Ihr Club in Zukunft ein Club sein, aber auch eine Sauna.
Pieter B
13

Der erste Ansatz weist auf primitive Besessenheit hin . Da Sie Ints und Strings weitergeben, kann der Programmierer sehr leicht einen Fehler machen (z. B. Übergabe einer clubId an den Parameter terminalId). Dies führt dazu, dass Fehler schwer zu finden sind.

Im zweiten Beispiel ist es unmöglich, einen Club zu passieren, wenn ein Terminal erwartet wird. Dies würde zu einem Fehler bei der Kompilierung führen.

Trotzdem würde ich immer noch schauen string invoice. Ist eine Rechnung wirklich eine Zeichenfolge? Was heißt amountdas Dies ist eher ein Geldwert.

Sie haben in Ihrer Frage erwähnt, "was über das Kabel gesendet wird, sind nur die IDs." Dies ist korrekt, aber lassen Sie diese Anforderung Ihre Domain nicht trüben.

Die beste Erklärung, die ich für diesen Ansatz gesehen habe, war in Regel 3 der Objektkalisthenik :

Ein Int für sich ist nur ein Skalar, hat also keine Bedeutung. Wenn eine Methode ein int als Parameter verwendet, muss der Methodenname die gesamte Arbeit zum Ausdrücken der Absicht erledigen. Wenn dieselbe Methode eine Stunde als Parameter benötigt, ist es viel einfacher zu sehen, was los ist. Kleine Objekte wie dieses können Programme wartbarer machen, da es nicht möglich ist, ein Jahr an eine Methode zu übergeben, die einen Stundenparameter verwendet. Mit einer primitiven Variablen kann der Compiler Ihnen nicht helfen, semantisch korrekte Programme zu schreiben. Mit einem Objekt, auch einem kleinen, geben Sie sowohl dem Compiler als auch dem Programmierer zusätzliche Informationen darüber, was der Wert ist und warum er verwendet wird.

MattDavey
quelle
Der zweite Ansatz wird also bevorzugt? Auch wenn es ein Clubobjekt gibt, bei dem nur die ID-Eigenschaft gefüllt ist?
Mithir
Dies scheint ein zufälliger Blog zu sein. Es gibt keine Beweise dafür, was bevorzugt wird. Wen interessiert es wirklich, was bevorzugt wird? Tun Sie, was für Sie funktioniert
James
@ James Es gibt keine endgültige Antwort auf diese Frage, zumal das OP uns nicht sehr viel Kontext gegeben hat. Jeder, der kategorisch behauptet, ein Ansatz sei dem anderen vorzuziehen, tut dem OP einen schlechten Dienst. Es ist nicht so schwarz und weiß.
MattDavey
1
@ James Ich habe nur darauf hingewiesen, dass der erste Ansatz es sehr einfach macht, schwer zu findende Fehler einzuführen. Ich sage nicht, dass primitive Typen schlecht sind, aber der Zweck primitiver Typen besteht darin, sinnvolle Domänentypen aufzubauen. Ihre Verwendung außerhalb dieses Kontextes ist genau die Definition des Geruchs des primitiven Obsession-Codes.
MattDavey
5
@ James: Was MattDavey gesagt hat, ist eine bekannte Tatsache. Er sagt nicht, dass native Typen schlecht sind, was er sagt, dass dies: someMethod (int, int, int, string, decimal) für einen Client viel schwieriger zu verstehen und zu verwenden ist als someMethod (Club, Terminal, Card, String) , dezimal)
c_maker
2

Es gibt keine richtige Antwort auf diese Frage. Jede Option könnte für den Job geeignet sein. Na ja, fast auf jeden Fall hat das Rechnungsargument eine Furche auf meiner Stirn aufgewirbelt. Ich habe keine Ahnung, was das vom Lesen des Codes ist.

Wenn Sie eine ID senden, müssen beide Systeme eng an das gekoppelt sein, was dies darstellt. ClubID ist der Schlüssel in der Clubtabelle. Mehr auf den Punkt gebracht, müssen sowohl Anrufer als auch Angerufene vereinbaren, wie die Clubtabelle heißt und in welcher Datenbank sie sich befindet. Wenn Sie diese Einschränkung nicht auferlegen möchten oder können, übergeben Sie das Objekt mit einer allgemeinen Beschreibung. native, serialisiert, xml, name = value was auch immer, eine INI-Datei :)

Das, wie Sie identifiziert haben, kostet Sie "über den Draht". Das zu vermeiden, indem Sie nur die Kennung senden, kostet Sie woanders. Welches Sie jetzt (oder später) am wenigsten verletzt, ist der Indikator für gut gegen schlecht.

Tony Hopkinson
quelle