Was sind die Vor- und Nachteile statischer Objekterstellungsmethoden gegenüber Konstruktoren?
class Foo {
private Foo(object arg) { }
public static Foo Create(object arg) {
if (!ValidateParam(arg)) { return null; }
return new Foo(arg);
}
}
Wenige, an die ich denken kann:
Vorteile:
- Geben Sie null zurück, anstatt eine Ausnahme auszulösen (benennen Sie es
TryCreate
). Dies kann den Code auf der Clientseite knapper und sauberer machen. Clients erwarten selten, dass ein Konstruktor ausfällt. - Erstellen Sie verschiedene Arten von Objekten mit klarer Semantik, z. B.
CreatFromName(String name)
undCreateFromCsvLine(String csvLine)
- Kann bei Bedarf ein zwischengespeichertes Objekt oder eine abgeleitete Implementierung zurückgeben.
Nachteile:
- Weniger auffindbar, schwieriger zu überfliegen.
- Einige Muster, wie die Serialisierung oder Reflexion sind schwieriger ( zum Beispiel
Activator<Foo>.CreateInstance()
)
design-patterns
dbkk
quelle
quelle
Foo x = Foo.TryCreate(); if (x == null) { ... }
). Die Behandlung einer ctor-Ausnahme ist (Foo x; try { x = new Foo(); } catch (SomeException e) { ... }
). Beim Aufrufen einer normalen Methode bevorzuge ich Ausnahmen gegenüber Fehlercodes, aber bei der ObjekterstellungTryCreate
erscheint dies sauberer.Name
und zu typisierenCsvLine
, als Anforderungen über Methodennamen auszudrücken. Auf diese Weise können Sie Create überladen. Die Verwendung von Zeichenfolgen für beide kann als "primitive Besessenheit" angesehen werden (vorausgesetzt, Sie haben diese Auswahl aus bekannten Leistungsgründen nicht getroffen). Schauen Sie sich Object Calisthenics an, um eine unterhaltsame Möglichkeit zu finden, dies zu erkunden.Antworten:
Der größte Nachteil bei statischen " Erstellern " ist wahrscheinlich die Einschränkung der Vererbung. Wenn Sie oder der Benutzer Ihrer Bibliothek eine Klasse von Ihrer ableiten
Foo
,Foo::Create()
wird dies ziemlich nutzlos. Alle dort definierten Logiken müssen im geerbten erneut geschrieben werdenCreate()
.Ich würde einen Kompromiss vorschlagen: Definieren Sie einen Konstruktor mit einer trivialen Objektinitialisierungslogik, die niemals fehlschlägt / wirft, und definieren Sie dann Ersteller mit Caching, alternativer Konstruktion usw. Dies lässt die Möglichkeit des Ableitens und Sie profitieren davon, Ersteller für eine bestimmte Klasse zu haben .
quelle
Erstellen ist eine Factory-Methode. Wenn ich dies für nötig halte, implementiere ich das Factory-Muster und definiere eine Schnittstelle zur Darstellung des Vertrags zum Erstellen des Objekts sowie eine implementierende Klasse, die dann bei Bedarf eingefügt wird. Dadurch bleiben die Vorteile des Verschiebens der Erstellungsverantwortung aus der Klasse erhalten, es werden jedoch die Einschränkungen bei der Objekterstellung außerhalb des Klassenkonstruktors vermieden (oder zumindest deutlicher).
quelle