Designfrage:Übergeben Sie die von Ihnen verwendeten Felder oder übergeben Sie das Objekt?

StackOverflow https://stackoverflow.com/questions/1092628

  •  11-09-2019
  •  | 
  •  

Frage

Ich sehe oft zwei widersprüchliche Strategien für Methodenschnittstellen, die grob wie folgt zusammengefasst werden:

// Form 1: Pass in an object.
double calculateTaxesOwed(TaxForm f) { ... }

// Form 2: Pass in the fields you'll use.
double calculateTaxesOwed(double taxRate, double income) { ... }

// use of form 1:
TaxForm f = ...
double payment = calculateTaxesOwed(f);

// use of form 2:
TaxForm f = ...
double payment = calculateTaxesOwed(f.getTaxRate(), f.getIncome());

Ich habe Befürworter der zweiten Form gesehen, insbesondere in dynamischen Sprachen, wo es möglicherweise schwieriger ist zu beurteilen, welche Felder verwendet werden.

Allerdings bevorzuge ich die erste Form deutlich:Es ist kürzer, es gibt weniger Spielraum für Fehler, und wenn sich die Definition des Objekts später ändert, müssen Sie nicht unbedingt die Methodensignaturen aktualisieren, sondern vielleicht einfach die Art und Weise ändern, wie Sie mit dem Objekt innerhalb der Methode arbeiten.

Gibt es für beide Formen einen zwingenden allgemeinen Fall?Gibt es klare Beispiele dafür, wann Sie das zweite Formular dem ersten vorziehen sollten?Gibt es SOLID- oder andere OOP-Prinzipien, auf die ich verweisen kann, um meine Entscheidung, eine Form gegenüber einer anderen zu verwenden, zu rechtfertigen?Ändert sich eine der oben genannten Antworten, wenn Sie eine dynamische Sprache verwenden?

War es hilfreich?

Lösung

In aller Ehrlichkeit es über die Methode in Frage abhängig ist.

Falls das Verfahren sinnvoll, ohne das Objekt, dann wird die zweite Form einfacher ist, wieder zu verwenden, und entfernt eine Kopplung zwischen den beiden Klassen.

Wenn die Methode für das Objekt verlässt sich dann fair genug, das Objekt übergeben.

Es ist wahrscheinlich ein gutes Argument für eine dritte Form, wo Sie eine Schnittstelle übergeben entwickelt, um mit dieser Methode zu arbeiten. Gibt Ihnen die Klarheit der ersten Form mit der Flexibilität der zweiten.

Andere Tipps

Es hängt von der Absicht Ihrer Methode.

Wenn die Methode ausgelegt ist arbeiten speziell mit diesem Objekt und nur dieses Objekt, übergeben Sie das Objekt. Er sorgt für eine schöne Verkapselung.

Wenn aber die Methode ist allgemeineren Zweck , werden Sie wahrscheinlich wollen einzeln die Parameter übergeben . Auf diese Weise ist das Verfahren eher wiederverwendet werden, wenn die Information kommt von einer anderen Quelle (das heißt verschiedene Arten von Objekten oder andere abgeleitete Daten).

ich die zweite Lösung wird dringend empfohlen - calculateTaxesOwed() einige Daten berechnet, daher braucht einige numerische Eingabe. Das Verfahren hat absolut nichts mit der Benutzeroberfläche zu tun und wiederum soll nicht eine Form als Eingabe Consum, weil Sie Ihre Geschäftslogik von der Benutzeroberfläche getrennt werden sollen.

Das Verfahren der Ausführung der Berechnung sollte (in der Regel) nicht einmal auf das gleiche Modul wie die Benutzeroberfläche gehören. In diesem Fall, dass Sie eine zirkuläre Abhängigkeit erhalten, weil die Benutzeroberfläche der Business-Logik und die Business-Logik erfordert erfordert die Benutzeroberfläche Form -. Ein sehr starken Anzeichen dafür, dass etwas nicht in Ordnung ist (aber immer noch Schnittstelle basierte Programmierung unter Verwendung gelöst werden könnte)

UPDATE

Wenn das Steuerformular kein Benutzeroberfläche Form ist, ändern sich die Dinge ein wenig. In diesem Fall schlage ich vor, den Wert unter Verwendung einer Instanzmethode GetOwedTaxes() oder Instanzeigenschaft OwedTaxes die TaxForm Klasse aussetzen, aber ich würde nicht eine statische Methode verwenden. Wenn kann die Berechnung an anderer Stelle wiederverwendet werden, so könnte man noch eine statische Hilfsmethode erstellen, die Werte aufwendig, nicht das Formular, und nennt diese Hilfsmethode aus der Instanzmethode oder Eigenschaft.

Ich glaube nicht, es wirklich darauf ankommt. Sie öffnen sich Auswirkungen auf die Seite, wenn Sie in dem Objekt passieren, wie es mutiert werden könnten. Dies könnte jedoch sein, was Sie wollen. Zur Milderung dieses (und Tests zu unterstützen) Sie sind wahrscheinlich besser Passieren der Schnittstelle anstatt der konkrete Typ. Der Vorteil ist, dass Sie nicht brauchen, um die Methodensignatur zu ändern, wenn Sie ein anderes Feld des Objekts zugreifen möchten.

Passing alle Parameter macht es klarer, was die Art Bedürfnisse, und könnte es einfacher zu testen machen (obwohl, wenn Sie die Schnittstelle verwenden, dies weniger ein Vorteil ist). Aber Sie werden mehr Refactoring haben.

jede Situation auf seine Verdienste Richter und der am wenigsten schmerzhafte Auswahl.

Passing kann die Argumente zu Unit-Test einfacher sein, , wie Sie benötigen, um ganze Objekte voller Daten nicht zu verspotten nur Funktionalität zu testen, die im Wesentlichen nur statische Berechnung. Wenn es nur zwei Felder verwendet wird, der das Objekt vielen, lehne ich mich würde auf nur jene Felder vorbei, alle anderen Faktoren gleich sind.

Wie gesagt, , wenn Sie mit sechs am Ende, sieben oder mehr Feldern, ist es Zeit, entweder das gesamte Objekt oder eine Teilmenge der Felder in einer „Nutzlast“ Klasse vorbei zu prüfen (oder Struktur / Wörterbuch, abhängig von der Art der Sprache). Lange Methode Signaturen ist in der Regel verwirrend.

Die andere Option ist es eine Klassenmethode zu machen, so dass Sie müssen nicht alles passieren. Es ist weniger bequem zu testen, aber eine Überlegung wert, wenn Ihre Methode immer nur auf einem TaxForm Objektdaten verwendet wird.

Ich weiß, dass dies weitgehend ein Artefakt des Beispiels verwendet und so kann es nicht in vielen realen Fällen gelten, aber, wenn die Funktion so stark auf eine bestimmte Klasse gebunden ist, dann sollte es nicht sein:

double payment = f.calculateTaxesOwed;

Es scheint mir sinnvoller, dass ein Steuerdokument die Verantwortung selbst für die Berechnung der relevanten Steuern eher, dass die Verantwortung fällt auf eine Nutzenfunktion führen würde, als wenn, zumal unterschiedliche Steuerformulare verschiedene Steuertabellen oder Berechnungsmethoden verwenden neigen.

Ein Vorteil der ersten Form ist

  1. Abstraction - Programmierung auf eine Schnittstelle statt Implementierung. Es macht die Wartung des Codes leichter auf lange Sicht weil Sie die Implementierung von TaxForm ändern kann den Client-Code, solange die Schnittstelle von TaxForm ohne Beeinträchtigung ändert sich nicht.

Dies ist das gleiche wie das „Einführung Parameter Objekt“ von Martin Fowler Buch über Refactoring. Fowler schlägt vor, dass Sie das Refactoring durchführen, wenn es eine Gruppe von Parametern, die zusammen geführt neigen zu werden.

Wenn Sie in dem Gesetz von Demeter glauben, dann würden Sie bevorzugen genau geben, was notwendig ist:

http://en.wikipedia.org/wiki/Law_of_Demeter

http://www.c2.com/cgi/wiki?LawOfDemeter

Die Trennung von UI und Daten manipuliert werden

In Ihrem Fall Sie eine Zwischenklasse fehlt, sagen, TaxInfo, die die Einheit besteuert werden. Der Grund dafür ist, dass UI (Formular) und Business-Logik (wie Steuersatz berechnet wird) ist auf zwei verschiedene „change tracks“, wechselt man mit Präsentationstechnik ( „das Web“, „Das Web 2.0“, „WPF“. ..), die anderen Änderungen mit Juristensprache. Definieren Sie eine klare Schnittstelle zwischen ihnen.


Allgemeine Diskussion, indem ein Beispiel:

eine Funktion Betrachten wir ein Bitmap für eine Visitenkarte zu erstellen. Ist der Zweck der Funktion

(1) // Formatiert eine Visitenkarte Titel aus Vornamen und Nachnamen

oder

(2) // Formatiert einen businnes Kartentitel von einem Person Datensatz

Die erste Option ist generisch, mit einer schwächeren Kopplung, die in der Regel vorzuziehen ist. Doch in vielen Fällen weniger robust gegenüber Änderungsanforderungen - z.B. betrachten „Fall 2017: add Personen Initial Visitenkarte“.

Ändern der Implementierung (Hinzufügen person.Initial) ist in der Regel einfacher und schneller als die Schnittstelle zu ändern.

Die Wahl ist letztlich, welche Art von Änderungen, die Sie erwarten: ist es wahrscheinlicher, dass mehr Informationen von einem Personrecord erforderlich ist, oder ist es wahrscheinlicher, dass Sie Visitenkarte Titel für andere Datenstrukturen als Person erstellen möchten

Wenn das „unentschieden“, anfd Sie nicht für einen bestimmten Zweck OPF können (1) oder (2) Ich würde eher gehen mit (2), für syntaktische Sauberkeit.

Wenn ich mich für eine der beiden Optionen entscheiden müsste, würde ich mich immer für die zweite Option entscheiden – was wäre, wenn Sie feststellen würden, dass Sie (aus welchem ​​Grund auch immer) die geschuldeten Steuern berechnen müssen, aber keine Instanz davon haben TaxForm?

Dies ist ein ziemlich triviales Beispiel, ich habe jedoch Fälle gesehen, in denen eine Methode, die eine relativ einfache Aufgabe ausführte, komplexe Eingaben hatte, die schwer zu erstellen waren, was die Verwendung der Methode weitaus schwieriger machte, als sie hätte sein sollen.(Der Autor hatte einfach nicht daran gedacht, dass andere Leute diese Methode vielleicht nutzen möchten!)

Persönlich würde ich, um den Code besser lesbar zu machen, wahrscheinlich beides haben:

double calculateTaxesOwed(TaxForm f) 
{
    return calculateTaxesOwed(f.getTaxRate(), f.getIncome());
}

double calculateTaxesOwed(double taxRate, double income) { ... }

Meine Faustregel lautet, wo immer möglich eine Methode zu haben, die genau die Eingaben entgegennimmt, die sie benötigt – es ist sehr einfach, Wrapper-Methoden zu schreiben.

Ich persönlich werde mit # 2 gehen, da es viel klarer aus ist, was es ist, dass das Verfahren notwendig. Vorbei an die TaxForm (wenn es ist, was ich denke, es ist, wie ein Windows Form) stinkende Art ist und ich ein wenig machen erschaudern (> _ <).

würde ich die erste Variante verwenden Sie nur, wenn Sie die Berechnung ein DTO spezifisch sind vorbei, wie IncomeTaxCalculationInfo Objekt, das das TaxRate und Einkommen und was sonst noch benötigt enthalten wird das Endergebnis in der Methode zu berechnen, aber nie so etwas wie ein Windows / Web Form.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top