Frage

Was ist besser Praxis, wenn mehrere Methoden definieren, die die gleiche Form von Daten mit verschiedenen Filtern zurückgeben? Explizite Methodennamen oder überladene Methoden?

Zum Beispiel. Wenn ich einige Produkte haben, und ich bin aus einer Datenbank ziehen

explizite Art und Weise:

public List<Product> GetProduct(int productId) {    // return a List    }
public List<Product> GetProductByCategory(Category category) {    // return a List    }
public List<Product> GetProductByName(string Name ) {    // return a List    }

überlastet Art und Weise:

public List<Product> GetProducts() {    // return a List of all products    }
public List<Product> GetProducts(Category category) { // return a List by Category }
public List<Product> GetProducts(string searchString ) { // return a List by search string }

Ich weiß, Sie in ein Problem bekommen kann mit ähnliche Signaturen , aber wenn Sie auf Objekte anstelle von Basistypen (String, int, char, Datetime, etc.), die wird dies weniger ein Problem. So ... ist es eine gute Idee, Überlastung ein Verfahren die Anzahl der Methoden zu reduzieren, die Sie haben und aus Gründen der Klarheit, oder sollte jede Methode dass filtert die Daten, die eine andere Art und Weise haben eine andere Methode Namen

War es hilfreich?

Lösung

Ja, Überlastung kann leicht überstrapaziert werden.

Ich habe festgestellt, dass der Schlüssel zum Ausarbeiten, ob eine Überlastung gerechtfertigt ist oder nicht, das Publikum ist zu berücksichtigen - nicht der Compiler, aber der Wartung Programmierer, der entlang in Wochen / Monaten / Jahren kommen wird und hat zu verstehen, was der Code versucht, zu erreichen.

Eine einfache Methode Namen wie GetProducts () ist klar und verständlich, aber es macht eine Menge ungesagt lassen.

In vielen Fällen, wenn der Parameter auf GetProducts () übergeben und benannt ist, wird der Hausmeister der Lage sein, um herauszufinden, was die Überlastung tut - aber das ist auf gute Namensgebung Disziplin unter Berufung auf dem Verwendungsort, die man‘ t erzwingen. Was können Sie erzwingen ist der Name der Methode sie rufen.

Die Richtlinie, die ich folgen soll nur Überlastung Methoden, wenn sie austauschbar sind - wenn sie das gleiche tun. Auf diese Weise stört mich nicht, welche Version der Verbraucher meiner Klasse aufruft, wie sie gleichwertig sind.

Zur Veranschaulichung ich würde gerne Überlastungen für eine DeleteFile () -Methode verwenden:

void DeleteFile(string filePath);
void DeleteFile(FileInfo file);
void DeleteFile(DirectoryInfo directory, string fileName);

Doch für Ihre Beispiele, würde ich getrennte Namen verwenden:

public IList<Product> GetProductById(int productId) {...}
public IList<Product> GetProductByCategory(Category category) {...}
public IList<Product> GetProductByName(string Name ) {...}

die vollständigen Namen zu haben, macht den Code explizit für den Hausmeister (der gut könnte ich sein). Es vermeidet Probleme mit Unterschrift Kollisionen mit:

// No collisions, even though both methods take int parameters
public IList<Employee> GetEmployeesBySupervisor(int supervisorId);
public IList<Employee> GetEmployeesByDepartment(int departmentId);

Es gibt auch die Möglichkeit, für jeden Zweck einzuführen Überlastung:

// Examples for GetEmployees

public IList<Employee> GetEmployeesBySupervisor(int supervisorId);
public IList<Employee> GetEmployeesBySupervisor(Supervisor supervisor);
public IList<Employee> GetEmployeesBySupervisor(Person supervisor);

public IList<Employee> GetEmployeesByDepartment(int departmentId);
public IList<Employee> GetEmployeesByDepartment(Department department);

// Examples for GetProduct

public IList<Product> GetProductById(int productId) {...}
public IList<Product> GetProductById(params int[] productId) {...}

public IList<Product> GetProductByCategory(Category category) {...}
public IList<Product> GetProductByCategory(IEnumerable<Category> category) {...}
public IList<Product> GetProductByCategory(params Category[] category) {...}

-Code viel mehr gelesen als geschrieben steht - auch wenn Sie nicht in der Quellcodeverwaltung nach dem ersten Scheck an den Code zurückkommen, wirst du immer noch, dass Codezeile ein paar Dutzend Mal zu lesen, während Sie schreiben den Code, der folgt.

Schließlich, es sei denn Sie Wegwerf-Code schreiben, müssen Sie für andere Menschen fordern Sie den Code aus anderen Sprachen ermöglichen. Es scheint, dass die meisten Business-Systeme in der Produktion am Ende bleiben weit über ihr Haltbarkeitsdatum. Es kann sein, dass der Code, der im Jahr 2016 die Klasse verbraucht endet in VB.NET geschrieben, C # 6.0, F # oder etwas völlig Neues, das bisher noch nicht erfunden. Es kann sein, dass die Sprache nicht Überlastungen nicht unterstützt.

Andere Tipps

Soweit ich das beurteilen kann, werden Sie nicht weniger Methoden haben, nur wenige Namen. Ich ziehe es im Allgemeinen die überladene Methode System der Namensgebung, aber ich glaube nicht, dass es so lange wirklich viel Unterschied macht, wie Sie kommentieren und dokumentieren Sie den Code gut (die Sie in jedem Fall tun sollten).

Können Sie es Übernutzung? na ja, ja, das ist wahr.

Allerdings sind die Beispiele, die Sie gegeben haben, sind perfekte Beispiele für bei der Methode Überlastung zu verwenden. Sie alle haben die gleiche Funktion, warum sie verschiedene Namen nur geben, weil Sie verschiedene Arten, um sie vorbei sind.

Die Hauptregel ist die klarste tun, einfachste Sache zu verstehen. Sie Überlastung nicht nur verwenden, glatt oder klug zu sein, tun Sie es, wenn es Sinn macht. Andere Entwickler könnten auch auf diesem Code arbeiten. Sie wollen es so einfach wie möglich zu machen für sie den Code zu holen und verstehen und in der Lage sein, Änderungen zu implementieren, ohne Fehler zu implementieren.

Ich mag Überlastung meine Methoden, so dass später in der Intellisense ich nicht eine Million der gleichen Methode haben. Und es scheint logisch für mich ist es einfach, anstatt überlastet zu haben, nachdem es anders ein Dutzend Mal genannt.

Eine Sache, die Sie betrachten können, ist, dass Sie nicht überladene Methoden wie Operation Verträge in einem WCF-Web-Service aussetzen können. Also, wenn Sie denken, dass Sie immer, dies tun müssen, wäre es für die Verwendung von verschiedenen Methodennamen ein Argument sein.

Ein weiteres Argument für verschiedene Methodennamen ist, dass sie leicht auffindbar mehr sein können mit Intellisense.

Aber es gibt Vor-und Nachteile für beide Wahl -. Alles Design Trade-off

Sie müssen wahrscheinlich einige projektweiten Standards. Ich persönlich finde die überladenen Methoden viel leichter zu lesen. Wenn Sie die IDE-Unterstützung haben, gehen für sie.

Der Punkt der Überlastung die Lernkurve von jemandem mit Ihrem Code zu erleichtern ... und Ihnen zu erlauben, Namensschemata zu verwenden, die den Benutzer darüber informieren, was das Verfahren der Fall ist.

Wenn Sie zehn verschiedene Methoden, die alle eine Sammlung von Mitarbeitern zurück, dann zehn verschiedene Namen zu erzeugen, (Vor allem, wenn sie mit verschiedenen Buchstaben beginnen!) Bewirkt, dass sie erscheinen, als mehrere Einträge in Ihren Benutzern intellisense Dropdown die Verlängerung Länge der absenkbaren und die Unterscheidung zwischen dem Satz von zehn Methoden versteckt, die alle einen Mitarbeiter Sammlung zurückzukehren, und was auch immer andere Methoden in der Klasse sind ...

Denken Sie darüber nach, was bereits von dem FRAMEWORK erzwungen wird, sagen Konstrukteure und Indexer ... Sie sind alle den gleichen Namen zu haben, gezwungen, und man kann nur ein Vielfaches erstellen, indem sie eine Überlastung ...

Wenn Sie sie überlasten, werden sie alle erscheinen als ein, mit ihren unterschiedlichen Signaturen und Kommentare aus zu tthe Seite.

Sie sollten nicht zwei Methoden überlasten, wenn sie unterschiedliche oder nicht verwandte Funktionen ausführen ...

In Bezug auf die Verwirrung, die existieren kann, wenn Sie nach Typ zwei Methoden mit derselben Signatur zu überlasten wollen wie in

public List<Employee> GetEmployees(int supervisorId);
public List<Employee> GetEmployees(int departmentId); // Not Allowed !!

Nun können Sie separate Typen als Wrapper für die säumige Kern-Typ erstellen, um die Signaturen zu unterscheiden ..

  public struct EmployeeId 
  { 
      private int empId;
      public int EmployeeId { get { return empId; } set { empId = value; } }
      public EmployeeId(int employeId) { empId = employeeId; }
  }

  public struct DepartmentId 
  {
   // analogous content
  }

 // Now it's fine, as the parameters are defined as distinct types...
 public List<Employee> GetEmployees(EmployeeId supervisorId);
 public List<Employee> GetEmployees(DepartmentId  departmentId);

Eine andere Möglichkeit ist es, eine Abfrage-Objekt zu verwenden, um die „WHERE-Klausel“ zu bauen. Sie würden also nur eine Methode wie folgt aussehen:

public List<Product> GetProducts(Query query)

Das Query-Objekt enthält die condidition in einer objektorientierten Art und Weise zum Ausdruck gebracht. Die GetProducts erhält die Abfrage von "Parsen" Query-Objekt.

http://martinfowler.com/eaaCatalog/queryObject.html

Ich habe gesehen, Überlastung überstrapaziert, wenn Sie in den Argumenten der Methode nur feine Unterschiede haben. Zum Beispiel:

public List<Product> GetProduct(int productId) { // return a List  }
public List<Product> GetProduct(int productId, int ownerId ) { // return a List  }
public List<Product> GetProduct(int productId, int vendorId, boolean printInvoice) { // return a List  }

In meinem kleinen Beispiel, es wird schnell klar, ob das zweite int Argument sollte der Eigentümer oder Kunden-ID sein.

Ein kurzer Blick auf die Rahmen sollten Sie überzeugen, dass zahlreiche Überlastungen ein akzeptierter Zustand ist. Angesichts der unzähligen Überlastungen, die Design von Überlastungen für die Benutzerfreundlichkeit wird durch Abschnitt 5.1.1 der Microsoft Framework Design Guidelines (Kwalina und Abrams, 2006) direkt angesprochen. Hier ist eine kurze Précis dieses Abschnitts:

  • versuchen beschreibende Parameternamen zu verwenden, um den Standard durch kürzere Überlastungen verwendet, um anzuzeigen.

  • VERMEIDEN willkürlich Parameternamen in Überlastungen variiert wird.

  • VERMEIDEN inkonsistent zu sein in der Reihenfolge der Parameter in überladenen Mitgliedern.

  • machen nur die längste Überlastung virtuelle (wenn Dehnbarkeit erforderlich ist). Kürzere Überlastungen sollten einfach auf eine längere Überlastung rufen durch.

  • NICHT Verwendung ref oder out Parameter Mitglieder zu überlasten.

  • erlaubt null für optionale Argumente übergeben werden.

  • Verwendung Mitglied Überlastung nicht Mitglieder mit Standardargumenten definieren.

Ja, Sie können es überstrapazieren, aber hier ist ein weiteres Konzept, das die Verwendung von unter Kontrolle halten helfen könnte ...

Wenn Sie .NET verwenden 3.5+ und mehrere Filter Sie gelten müssen wahrscheinlich besser nutzen IQueryable und Verkettungs d

GetQuery<Type>().ApplyCategoryFilter(category).ApplyProductNameFilter(productName);

Auf diese Weise können die Filterlogik über wiederverwenden können und über egal wo Sie es brauchen.

public static IQueryable<T> ApplyXYZFilter(this IQueryable<T> query, string filter)
{
     return query.Where(XYZ => XYZ == filter);
} 

Sie können mit so viel überladen, wie Sie wollen. als auch von den besten Praktiken Sicht empfiehlt es sich, mit dem Sie Überlastung, wenn Sie versuchen, die gleichen „Operation“ (holistisch) auf den Daten durchzuführen. Z.B. getProduct ()

Auch wenn Sie Java API sehen, Overloading ist überall. Sie würden nicht eine größere Zustimmung als das finden.

Overloading ist wünschenswert, polymorphes Verhalten. Es hilft dem menschlichen Programmierer den Methodennamen erinnern. Wenn explizite redundant mit dem Typ-Parameter ist, dann ist es schlecht. Wenn der Typ Parameter implizieren nicht, was die Methode tut, dann explizit beginnt Sinn zu machen.

In Ihrem Beispiel ist getProductByName der einzige Fall, in dem expliziten Sinn machen könnte, da Sie mögen vielleicht Produkt durch eine andere Zeichenfolge zu bekommen. Dieses Problem wurde durch die Mehrdeutigkeit von primitiven Typen verursacht werden; getProduct (Name n) könnte eine bessere Überlastung Lösung in einigen Fällen sein.

Ja, Sie können es überstrapazieren. In Ihrem Beispiel wäre es wie die erste scheint und dritter wahrscheinlich ein einzelnes Element zurückkehren würde, wo die zweiten mehr zurückkehren würde. Wenn das richtig ist, dann nennen würde ich die ersten und dritten getProduct und die zweite GetProducts oder GetProductList

, wenn dies nicht der Fall ist und alle drei Rückkehr mehrere (wie in, wenn Sie übergeben es ProductId 5, es alle Elemente mit 5 in der productid zurückgibt, oder gibt alle Elemente mit dem String-Parameter in seinem Namen), dann würde ich nennen alle drei GetProducts oder GetProductList und alle von ihnen außer Kraft setzen.

In jedem Fall sollte der Name widerspiegeln, was die Funktion tut, so ist es getProduct (Singular) aufrufen, wenn es eine Liste der Produkte liefert keine gute Funktionsnamen machen. IMNSHO

Ich bin ein totaler Fan der „explicit“ Art und Weise: Geben jeder Funktion einen anderen Namen. Ich habe Refactoring sogar einige Code, die viele Add(...) Funktionen in der Vergangenheit hatte, zu AddRecord(const Record&), AddCell(const Cell&), etc.

Ich denke, das hilft, einige Verwirrungen, unbeabsichtigte Abgüsse (in C ++, zumindest) und Compiler-Warnungen zu vermeiden, und es verbessert die Klarheit.

Vielleicht in einigen Fällen müssen Sie die andere Strategie. Ich habe nicht eine noch angetroffen werden.

Wie wäre es

public IList<Product> GetProducts() { /* Return all. */}

public IList<Product> GetProductBy(int productId) {...}
public IList<Product> GetProductBy(Category category) {...}
public IList<Product> GetProductBy(string Name ) {...}

Und so weiter?

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