Jakie są zalety i wady posiadania statycznych metod tworzenia obiektów nad konstruktorami?
class Foo {
private Foo(object arg) { }
public static Foo Create(object arg) {
if (!ValidateParam(arg)) { return null; }
return new Foo(arg);
}
}
Niewiele mogę wymyślić:
Plusy:
- Zwraca null zamiast zgłaszania wyjątku (nazwij go
TryCreate
). Może to sprawić, że kod będzie bardziej zwięzły i czysty po stronie klienta. Klienci rzadko oczekują awarii konstruktora. - Twórz różne rodzaje obiektów z wyraźną semantyką, np.
CreatFromName(String name)
ICreateFromCsvLine(String csvLine)
- W razie potrzeby może zwrócić buforowany obiekt lub pochodną implementację.
Cons:
- Mniej wykrywalny, trudniejszy do przeglądania kod.
- Niektóre wzorce, takie jak serializacja lub odbicie są trudniejsze (np.
Activator<Foo>.CreateInstance()
)
design-patterns
dbkk
źródło
źródło
Foo x = Foo.TryCreate(); if (x == null) { ... }
). Obsługa wyjątku ctor to (Foo x; try { x = new Foo(); } catch (SomeException e) { ... }
). Podczas wywoływania normalnej metody wolę wyjątki od kodów błędów, ale przy tworzeniu obiektówTryCreate
wydaje się czystsze.Name
i pisaćCsvLine
, niż wyrażać wymagania za pomocą nazw metod. Pozwoliłoby to na przeciążenie Utwórz. Używanie ciągów znaków w obu przypadkach może być uważane za „prymitywną obsesję” (zakładając, że nie dokonałeś tego wyboru ze znanych powodów wydajności). Sprawdź Object Calisthenics, aby uzyskać zabawny sposób na zbadanie tego.Odpowiedzi:
Największą wadą statycznych „ twórców ” jest prawdopodobnie ograniczenie dziedziczenia. Jeśli ty lub użytkownik twojej biblioteki wyprowadzasz klasę z twojej
Foo
,Foo::Create()
staje się prawie bezużyteczny. Cała zdefiniowana tam logika będzie musiała zostać przepisana ponownie w odziedziczonymCreate()
.Sugerowałbym kompromis: zdefiniuj konstruktor z trywialną logiką inicjowania obiektu, która nigdy nie zawiedzie / wyrzuca, następnie zdefiniuj twórcę (-ów) z buforowaniem, alternatywną konstrukcją itp. To pozostawia możliwość czerpania, a Ty zyskujesz mając twórców dla danej klasy .
źródło
Utwórz to metoda fabryczna. Kiedy czuję taką potrzebę, wdrażam wzorzec Factory i definiuję interfejs do reprezentowania kontraktu na tworzenie obiektu, a także klasę implementacyjną, która jest następnie wprowadzana w razie potrzeby. Zachowuje to zalety przenoszenia odpowiedzialności za tworzenie poza klasę, ale unika (lub przynajmniej czyni bardziej oczywistym) ograniczeń wykonywania tworzenia obiektów poza konstruktorem klasy.
źródło