2014-06-20 16 views
12

Właśnie zaktualizowane Visual Studio 2013 i zauważyłem, że w szablonie projektu dla aplikacji MVC klasa ApplicationDbContext teraz ma statyczną metodę, która po prostu wywołuje konstruktor:Czy istnieje jakaś korzyść (semantyczna lub inna) do korzystania z metody statycznej, która wywołuje konstruktor?

public static ApplicationDbContext Create() 
{ 
    return new ApplicationDbContext(); 
} 

Wydaje się bałaganu do mnie, ale mogę sobie wyobrazić istnieje jakiś semantyczny powód, dla którego powinienem teraz zacząć używać ApplicationDbContext.Create() zamiast new ApplicationDbContext(). Czy są jakieś korzyści?

+1

To wydaje się złym realizacji fabryce. –

+4

Czy konstruktor jest prywatny? ... Jest to wzorzec używany do powstrzymania konsumenta przed właśnie tworzeniem obiektu bez określania tego, co jest wymagane - zmuszając go do użycia metody statycznej. Jasne, ten wydaje się bezużyteczny - ale jeśli chcesz go przedłużyć, konfiguracja jest dla ciebie. –

+0

Konstruktor nie jest prywatny. – regularmike

Odpowiedz

17

Właściwie. tak.

W twoim konkretnym przypadku, zawijanie go w ten sposób umożliwia szybkie rozpoczęcie łączenia z logiką, na przykład tworzenie ApplicationDbContext i singleton lub obsługiwanie wyjątku w typowy sposób dla całej aplikacji. Ponieważ konstruktor nie może zwrócić wartości null, może to być bardzo ważne, aby móc przechwycić wyjątek i zwrócić wartość null.

Tuple.Create to główny przykład wnioskowania ogólnego, który nie działa z Konstruktorami. W ten sposób można powiedzieć

Tuple.Create(Item1, Item2.. ItemN); 

a niech typy kompilator wywnioskować, zamiast

new Tuple<T1, T2...Tn>(Item1, Item2...ItemN); 

który jest bardziej gadatliwy i zajmuje nieco więcej pracy, jeśli chcesz, aby przełączyć się na jeden z tych typów.

Istnieje również przypadek typów anonimowych, których nie można jednoznacznie określić, a zatem nie można ich używać w nowych wyciągach. Specjalnie miałem okazję, gdy podczas wyszukiwania złożeń dla określonego Atrybutu do łączenia struktury poleceń, chciałem wykonać wyliczanie (w tym przypadku Kolejka) z anonimowego typu podczas wyszukiwania, aby powiązać odwołania klasowe z ich konstruktorem i argumenty łańcuchowe, zamiast szukać ich za każdym razem, gdy są potrzebne. Ponieważ mogę ponownie zastosować wnioskowanie ogólne w metodzie, udało mi się owijać konstruktora metodą rozszerzenia i wykonać zadanie.

Istnieją również przypadki dla wzorów singleton, w których chcesz, aby metoda "GetInstance" zwykle tworzyła wartość lub otrzymała jedną, jeśli istnieje. Nie może się zakwalifikować, ponieważ ma nieco więcej niż zawijanie konstruktora.

Ponadto istnieje wiele przypadków, w których można chcieć kontrolować procedury wdrażania, takie jak narzucanie ich na inne wątki, rejestrowanie ich w bazie danych, które mają zostać cofnięte w późniejszym czasie, lub podłączanie systemu uprawnień, z których wszystkie mogą należy zrobić, tworząc opakowanie konstruktora i dodając kilka linii logiki, a następnie prywatyzując konstruktor, aby uniknąć jego bezpośredniego wywoływania.

Są też przypadki, w których stworzyłem metodę fabryczną, która deleguje do znanych dzieci, aby zapewnić inną implementację zwracanego interfejsu lub streszczenia na podstawie podanych parametrów. Dodatkową zaletą jest możliwość ukrywania klas implementujących - klasa Type i interfejs IEnumerable wykorzystują ten wzorzec.

+3

Po prostu sidenote: Wnioskowanie o parametrach typu konstruktora (pozwalając na 'nowy Tuple (1, 2)') jest jedną z oczekiwanych nowych funkcji w C# 6. – Mormegil

+0

To jest świetna odpowiedź. Chciałbym wiedzieć, że nie powiedziałem jednoznacznie, czy istnieje jakikolwiek powód, dla którego użyłbyś statycznej metody, jak teraz. Jeśli nie, to przypuszczam, że jest tam tylko na wypadek, gdybyś go potrzebował, co wydaje się niepotrzebne (pomimo zachęcania do korzystania z korzystnych wzorców) dla szablonu projektu, który staje się bardziej zagracony w każdym wydaniu. – regularmike

6

Ten wzorzec może być bardzo przydatny, szczególnie jeśli korzystasz z prywatnego konstruktora i zwróci interfejs typu typu z poziomu Utwórz, a nie konkretny.

private ApplicationDbContext() 
{ 

} 

public static IApplicationDbContext Create() 
{ 
    return new ApplicationDbContext(); 
} 

Teraz konsumenci Twojej klasy nie są w stanie polegać na konkretnej realizacji - mogą polegać tylko na abstrakcji.

+0

Powszechnie określa się to mianem wzoru metody fabrycznej. http://www.oodesign.com/factory-method-pattern.html – Gusdor

0

Zawijanie konstruktora metodami statycznymi (metody tworzenia) pozwala wybrać konkretną nazwę przekazującą informacje. Można również utworzyć kilka metod z tym samym podpisem parametru, takich jak CreateX(float f) i CreateY(float f), których nie można wykonywać z konstruktorami.

Sytuacja, w której jest to naprawdę użyteczne, to np. do tworzenia struktur reprezentujących wielkości fizyczne, które mogą mieć kilka jednostek, takich jak czas, długość lub waga. W tym przypadku można użyć metod tworzenia, aby wymusić na programistach jednoznaczne określenie jednostki, zamiast tylko przekazywać liczbę bez jednostek do pojedynczego konstruktora (który zakłada określoną jednostkę, a jej pomylenie może mieć wartość huge consequences).

Przykład:

public struct Length 
{ 
    private const double MetersPerYard = 0.9144; 
    private double _meters; 

    private Length(double meters) 
    { 
    _meters = meters; 
    } 

    public static Length FromMeters(double meters) 
    { 
    return new Length(meters); 
    } 

    public static Length FromYards(double yards) 
    { 
    return new Length(yards*MetersPerYard); 
    } 

    public double Meters 
    { 
    get { return _meters; } 
    } 

    public double Yards 
    { 
    get { return _meters/MetersPerYard; } 
    } 
} 

Albo spojrzeć na TimeSpan i metod jak FromMinutes, FromSeconds itp