2009-09-26 13 views
11

Przyjrzałem się prostszym aplikacjom, takim jak Nerddinner i ContactManager, a także bardziej skomplikowanym, takim jak Kigg. Rozumiem te prostsze, a teraz chciałbym zrozumieć bardziej złożone.Przeniesienie mojego MVC na wyższy poziom: DI i Unit of Work

Zazwyczaj prostsze aplikacje mają klasy repozytoriów i interfejsy (tak luźno powiązane, jak się da) na szczycie LINQtoSQL lub Entity Framework. Repozytoria są wywoływane przez kontrolery w celu wykonania niezbędnych operacji związanych z danymi.

Jeden wspólny wzór widzę kiedy zbadać bardziej skomplikowanych aplikacji, takich jak Kigg lub Oxite jest wprowadzenie (Jestem tylko zarysowania powierzchni tutaj, ale muszę zacząć gdzieś):

  • IOC di (w Kigg użytkownika sprawa Unity)
  • WWW Zapytanie Lifetime
  • jednostka pracy

Oto moje pytania:

Rozumiem, że aby naprawdę mieć luźno powiązaną aplikację, trzeba użyć czegoś takiego jak Unity. Ale wydaje się, że w momencie wprowadzenia Unity do miksu musisz również wprowadzić Lifetime Manager Web Request. Dlaczego? Dlaczego aplikacje przykładowe, takie jak Nerddinner, nie mają Web Lifetime Manager? Co dokładnie robi? Czy to jest rzecz specyficzna dla Jedności?

Drugi wzór, jaki zauważam, to wprowadzenie Jednostki Pracy. Znowu to samo pytanie: dlaczego Nerddinner lub ContactManager nie używają jednostki pracy? Zamiast tego te aplikacje używają klas repozytoriów na Linq2Sql lub Entity Framework do manipulowania danymi. Brak oznak jakiejkolwiek Jednostki Pracy. Czym dokładnie jest i dlaczego powinno się go używać?

Dzięki

Poniżej znajduje się przykład DI w Nerddiner na poziomie DinnersController:

public DinnersController() 
     : this(new DinnerRepository()) { 
    } 

    public DinnersController(IDinnerRepository repository) { 
     dinnerRepository = repository; 
    } 

Więc mam prawo przypuszczać, że ze względu na pierwszy konstruktor kontroler "posiada" THE DinnerRepository i będzie zatem zależeć od czasu życia kontrolera, ponieważ jest tam zadeklarowany?

Odpowiedz

3

Z Linq-SQL jest używany bezpośrednio, kontroler posiada odniesienie do kontekstu danych . Zwykle jest to prywatne odwołanie wewnątrz kontrolera, a więc jest tworzone jako część jego konstrukcji. W zarządzaniu na całe życie nie ma potrzeby, ponieważ jest w jednym miejscu.

Jednak, gdy używasz kontenera IoC, twoje repozytorium danych jest tworzone poza kontrolerem. Ponieważ kontener IoC, który je tworzy, nie wie, jak i jak długo zamierzasz używać utworzonego obiektu, wprowadzana jest strategia na całe życie.

Na przykład kontekst danych (repozytorium) jest zwykle tworzony na początku żądania WWW i niszczony na końcu. Jednak w przypadku komponentów, które współpracują z zewnętrzną usługą sieciową lub jakimś statycznym narzędziem odwzorowującym (np. Rejestratorem), nie ma potrzeby tworzenia ich za każdym razem. Możesz więc powiedzieć, aby stworzyć je raz (tzn. Tryb życia singletlowego).

Wszystko to dzieje się, ponieważ pojemnik IoC (taki jak Unity) jest przeznaczony do obsługi wielu sytuacji i nie zna Twoich konkretnych potrzeb. Na przykład niektóre aplikacje używają transakcji "konwersacji", w których NHibernate (lub Entity Framework może) może trwać podczas kilku stron/żądań internetowych. Kontenery IoC pozwalają dostosować czas życia obiektów do własnych potrzeb. Ale jak powiedziałeś, to ma swoją cenę - ponieważ nie ma jednej, wcześniej zdefiniowanej strategii, musisz samemu wybrać jedną.

Dlaczego NerdDinner i inne aplikacje nie używają bardziej zaawansowanych technik, to po prostu dlatego, że mają na celu demonstrowanie funkcji MVC, a nie zaawansowanych zastosowań innych bibliotek. Pamiętam artykuł napisany w celu zademonstrowania jednej zaawansowanej funkcjonalności kontenera IoC - artykuł ten przełamał pewne zatwierdzone wzorce projektowe, takie jak rozdzielenie obaw - ale nie było to ważne, ponieważ wzorce projektowe nie były celem artykułu. To samo z prostymi aplikacjami demonstracyjnymi MVC - nie chcą, abyś ty, nowicjusz MVC, zagubił się w labiryntach IoC.

I nie polecam spojrzeć na Oxite jako przykład odniesienia design: http://codebetter.com/blogs/karlseguin/archive/2008/12/15/oxite-oh-dear-lord-why.aspx http://ayende.com/Blog/archive/2008/12/19/oxite-open-exchangable-informative-troubled-engine.aspx

+0

Dziękujemy! To pomogło. Zmieniłem moje pytanie na dole. Czy to masz na myśli mówiąc, że kontroler jest właścicielem odniesienia do kontekstu repozytorium/danych? – Thomas

+0

Niezupełnie. W NerdDinner używają dodatkowego konstruktora akceptującego IDinnerRepository, aby ułatwić testy jednostkowe. Ale tak, wciąż jest to kontroler (konstruktor bez parametrów) lub testy, które tworzą i są właścicielem obiektu repozytorium. Oboje umierają i nie ma innych użytkowników repozytorium; więc życie jest proste. Tak przy okazji, taka technika jest zła; możesz przeczytać więcej na ten temat tutaj: http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/03/how-not-to-do-dependency-injection-in-nerddinner.aspx (również jako google dla "IoC biedaka"). – queen3

+0

Argument Jimmy'ego Bogarda o tym, że jest to rażący przykład "IoC biedaka" jest tutaj wyjątkowo dobry. Komentarze są również dobre. Zdecydowanie warte przeczytania. –

0

Uważam, że większość, jeśli nie wszystkie pojemniki DI, dotykają koncepcji czasu życia. W zależności od zaistniałego scenariusza możesz chcieć, aby kontener zawsze zwracał to samo wystąpienie zarejestrowanego komponentu, podczas gdy dla innego komponentu możesz chcieć, aby zawsze zwracał nowe wystąpienie. Większość kontenerów pozwala ci również określić, że w określonym kontekście chcesz, aby zwracała to samo wystąpienie, itp.

Nie znam bardzo dobrze (do tej pory używałem Windsora i Autofaca), ale ja podejrzenie, że menedżer życia żądania WWW jest implementacją strategii na całe życie, w której to samo wystąpienie jest dostarczane przez kontener w trakcie trwania pojedynczego żądania internetowego. Podobne strategie znajdziesz w kontenerach takich jak Windsor.

Wreszcie, przypuszczam, że odnosisz się do Jednostki Pracy. Jednostka pracy to w istocie grupa działań, które chcesz odnieść sukces lub zakończyć się niepowodzeniem jako jedna atomowa transakcja biznesowa. Aby uzyskać bardziej formalny opis, spójrz na definition Martina Fowlera. Jest to koncepcja, która zyskała większą popularność w kontekście Domain Driven Design. Jednostka pracy śledzi zmiany, które stosujesz w takiej transakcji, a kiedy nadejdzie odpowiedni czas, zatwierdza te zmiany w jednej transakcji ACID. W NHibernate np., sesja obsługuje pojęcie jednostki pracy, a dokładniej śledzenia zmian, podczas gdy w Linq2SQL jest to Kontekst ...

Powiązane problemy