Ich habe ein Person-Objekt mit zwei Konstruktoren - einer nimmt einen int (personId), der andere einen String (logonName). Ich möchte einen anderen Konstruktor, der eine Zeichenfolge (badgeNumber) nimmt. Ich weiß, dass das nicht möglich ist, aber es scheint, dass es eine gemeinsame Situation ist. Gibt es einen anmutigen Umgang damit? Ich nehme an, dies würde für jede überladene Methode gelten. Code:
%Vor%... usw.
Sie könnten benutzerdefinierte Typen verwenden.
Erstellen Sie beispielsweise LogonName- und BadgeNumber-Klassen.
Dann sehen Ihre Funktionsdeklarationen wie ...
aus %Vor%Eine solche Lösung bietet Ihnen möglicherweise einen guten Ort, um die Geschäftslogik beizubehalten, die für das Format und die Verwendung dieser Zeichenfolgen gilt.
Sie haben vier Möglichkeiten, die ich mir vorstellen kann, von denen drei bereits von anderen benannt wurden:
Gehen Sie auf die Fabrikroute, wie von mehreren anderen hier vorgeschlagen. Ein Nachteil ist, dass Sie keine konsistente Benennung durch Überladen haben können (sonst hätten Sie das gleiche Problem), also ist es oberflächlich weniger sauber. Ein weiterer, größerer Nachteil besteht darin, dass es die Möglichkeit einer direkten Zuweisung auf dem Stapel ausschließt. Bei dieser Vorgehensweise wird alles auf dem Heap zugewiesen.
Benutzerdefinierte Objektwrapper. Dies ist ein guter Ansatz, und der, den ich empfehlen würde, wenn Sie bei Null anfangen. Wenn Sie viel Code verwenden, z. B. Badges als Strings, kann das Neuschreiben von Code dies zu einer nicht realisierbaren Option machen.
Fügen Sie der Methode eine Aufzählung hinzu, und geben Sie an, wie die Zeichenfolge behandelt werden soll. Dies funktioniert, erfordert jedoch, dass Sie alle vorhandenen Aufrufe so umschreiben, dass sie die neue Enumeration enthalten (obwohl Sie bei Bedarf einen Standard angeben können, um dies zu vermeiden).
Fügen Sie einen Dummy-Parameter hinzu, der nicht zur Unterscheidung der beiden Überladungen verwendet wird. z.B. Tack a bool
auf die Methode. Dieser Ansatz wird von der Standardbibliothek an einigen Stellen, z.B. std::nothrow
ist ein Dummy-Parameter für operator new
. Die Nachteile dieses Ansatzes sind, dass es hässlich ist und dass es nicht skaliert.
Wenn Sie bereits eine große Basis an vorhandenem Code haben, würde ich empfehlen, entweder die Enumeration hinzuzufügen (möglicherweise mit einem Standardwert) oder den Dummy-Parameter hinzuzufügen. Weder ist schön, aber beide sind ziemlich einfach nachzurüsten.
Wenn Sie bei Null anfangen oder nur eine kleine Menge Code haben, würde ich die benutzerdefinierten Objektwrapper empfehlen.
Die Factory-Methoden wären eine Option, wenn Sie Code verwenden, der die rohen badge
/ logonName
-Strings stark verwendet, aber nicht die Person
-Klasse.
Wenn Sie C # 3.0 verwenden, können Sie Objektinitialisierer verwenden:
%Vor%Sie würden den Konstruktor wie folgt aufrufen:
%Vor%Sie können nicht zwei verschiedene Konstruktoren / Methoden mit der gleichen Signatur haben. Andernfalls kann der Compiler bestimmen, welche Methode ausgeführt werden soll.
Zack sagte , würde ich in Betracht ziehen, eine "Optionen" zu erstellen "Klasse, in der Sie die in einem benutzerdefinierten Typ enthaltenen Parameter tatsächlich übergeben können. Dies bedeutet, dass Sie so viele Parameter wie möglich übergeben können, und tun Sie, was Sie wollen mit den Optionen, seien Sie vorsichtig, dass Sie keine monolithische Methode erstellen, die alles versucht.Entweder das oder wählen Sie das Werksmuster ..
Sie können eine statische Factory-Methode verwenden:
%Vor%Ich denke nur an das, was Sie tun wollen, ist params, eines, das den Param-Typ beschreibt (ein enum mit LogonName, BadgeNumer, usw.) und das zweite ist der param-Wert.
Sie könnten zu einem Factory-Style-Muster wechseln.
%Vor%Oder verwenden Sie, wie vorgeschlagen, benutzerdefinierte Typen. Sie können auch etwas mit Generics hacken, aber ich würde es nicht für die Lesbarkeit empfehlen.