2010-04-21 11 views
32

Próbuję znaleźć poprawną definicję wzorca repozytorium.Schemat repozytoriów Standaryzacja metod

Mój oryginalny zrozumienie było to (bardzo dumbed dół)

  • oddzielnych obiektów biznesowych z danych Przedmioty
  • ujednolicić metody dostępu w warstwie dostępu do danych.

Naprawdę widziałem 2 różne implementacje i nie ma formalnych przykładów online, te, które widziałem są schowane w książkach.

Realizacja 1:

public Interface IRepository<T>{ 
     List<T> GetAll(); 
     void Create(T p); 
     void Update(T p); 
} 


public interface IProductRepository: IRepository<Product> { 
     //Extension methods if needed 
     List<Product> GetProductsByCustomerID(); 
} 

Realizacja 2:

public interface IProductRepository { 
     List<Product> GetAllProducts(); 
     void CreateProduct(Product p); 
     void UpdateProduct(Product p); 
     List<Product> GetProductsByCustomerID(); 
} 

Wskazówka pierwsza jest nazwą rodzajową Get/Aktualizacja/GETALL itd, drugi jest bardziej od tego, co Chciałbym zdefiniować "DAO".

Obie udostępniają ekstrakcję z jednostek danych. Co lubię, ale mogę zrobić to samo z prostym DAO. Jednak drugi element standaryzuje operacje dostępu, które widzę w wartości, jeśli wdrożysz to przedsiębiorstwo, ludzie z łatwością poznają zestaw metod dostępu do twojego repozytorium.

Czy nie mam racji zakładając, że standaryzacja dostępu do danych jest integralną częścią tego wzorca? Jeśli obie są poprawne, dlaczego warto wybrać implementację 2?

Rhino ma dobry artykuł na temat realizacji 1 i oczywiście MS ma mgliste definition a przykładem realizacji 2 jest here.

+0

Dla mnie _interface_ jest abstrakcją, tj. Przeciwieństwem _implementation_. Czy omawiamy tutaj tylko interfejsy, czy raczej klasy implementujące? – MEMark

Odpowiedz

14

Po drugie, cytat Fowlera cytowany przez oded. Chcę podkreślić, że powiedział "collection-jak interfejs" ". Sposób implementacji interfejsu podobnego do kolekcji jest z pewnością zależny od Ciebie, ale nie możesz ani nie musisz ukrywać faktu, że reprezentuje on zdalne źródło danych. W związku z tym różni się znacznie od kolekcji w pamięci, która nie musi przepłukiwać zmian do zdalnego magazynu danych. Mechanizm śledzenia zmian w ORMie lub w samodzielnym rozwiązaniu określa, jak przejrzyste może być to dokonywane dla osoby dzwoniącej. Usunięcia zwykle muszą być jawnie oznaczone, wstawki są wykrywalne (utrzymywanie przez osiągalność), a aktualizacje czasami muszą być wyraźnie oznaczone. Połącz to ze skomplikowanymi zależnościami twoich zagregowanych korzeni, a zobaczysz, że nie jest to zbyt zbieżne.

Nie ma czegoś takiego jak "implementacja repozytorium cannonical".

Odbywa się ciągła walka między adwokatami ogólnej klasy bazowej repozytorium a tymi, którzy wolą samodzielne wdrażanie każdego repozytorium. Podczas gdy ogólna implementacja jest atrakcyjna w prostych scenariuszach, bardzo często okaże się, że jest to bardzo nieszczelna abstrakcja. Na przykład niektóre z Twoich agregatów mogą być usuwane tylko miękko (cistomizable przez nadpisanie metody wirtualnej), podczas gdy inne mogą w ogóle nie obsługiwać operacji usuwania.

Upewnij się, że rozumiesz konsekwencje każdego podejścia przed podjęciem decyzji o wyborze trasy. Greg Young ma dobry post na temat zalet generycznych repozytoriów.

http://codebetter.com/blogs/gregyoung/archive/2009/01/16/ddd-the-generic-repository.aspx

7

Od Martin Fowler „Wzory Enterprise Application Architecture”, definicji repozytorium wzór:

pośredniczy pomiędzy warstwami domen i danych kartograficznych z wykorzystaniem interfejsu zbierającego podobny do dostępu do obiektów domeny.

Tak więc oba podejścia są prawidłowe.

+0

Domyślam się, że cała "kolekcja" jest niejasna, twierdziłbym, że kolekcja jak by to oznaczało Get/Update/Remove/etc nie .. ale zakładam, że spierałbyś się tak samo, jak Get = GetProduct – Nix

4

Jestem wielkim fanem ogólnego schematu repozytoriów, ale uważam, że powinniście zdecydowanie rozważyć nie bezpośrednie dziedziczenie z interfejsu, ponieważ może on stać się bardzo dużym ograniczeniem, zwłaszcza, że ​​wiele razy kod ogólnego interfejsu będzie taki sam jak można go zdefiniować w abstrakcyjnej klasie bazowej, dzięki czemu nie będzie można mieć więcej niż jednego ogólnego repozytorium wewnątrz klasy.

Polecam, aby Twój implementator IP ProductRepository uzyskał dostęp do generycznego IRepository<Product> poprzez delegację i wstrzyknął to za pomocą konstruktora, dzięki czemu możesz skomponować swoją klasę możliwie wielu IRepositentów i zgrupować je za jednym interfejsem w sposób, który ma sens.

pisałem bloga na ten temat, podczas gdy wyraźnie odwołuje NHibernate ten wzór może być stosowany do każdego rodzaju repozytorium: Creating a common generic and extensible NHiberate Repository version 2

2

Wraz z wprowadzeniem LINQ w .NET, rodzajowy repozytorium wzór staje się znacznie łatwiejsze do zrealizowania :

public interface IRepository<T> : IQueryable<T> 
{ 
    void Add(T item); 
    void Remove(T item); 
} 

aby zakwalifikować jako magazyn, a jedynie musi być w stanie uzyskać dostępu do danych w magazynie bazowego (łatwo wykonać IQueryable) i modyfikowania danych zawartych.

Można podać rozszerzenia interfejsu bazowego, aby zapewnić przechwyty dla zachowania bardziej specyficznego dla jednostki (na przykład podłączenie do wywołania procedury składowanej wywołania repozytorium opartego na języku SQL), ale większość operacji można wykonać za pomocą prostego interfejsu .

1

Dodatkowo do rodzajowego interfejsu repozytorium (realizacji 1) i swojej odmianie repozytorium ról specyficznych (realizacji 2) można również rozważyć metoda rodzajowa repozytorium

public interface IRepository 
{ 
    void Save<ENTITY>(ENTITY entity) where ENTITY : DomainEntity; 

    ENTITY Load<ENTITY>(Guid id) where ENTITY : DomainEntity; 

    IQueryable<ENTITY> Query<ENTITY>() where ENTITY : DomainEntity; 

    IQueryable<ENTITY> Query<ENTITY>(IDomainQuery<ENTITY> whereQuery) 
     where ENTITY : DomainEntity; 
} 

ten trzecia wersja pochodzi od this blogpost autorstwa Jimmy'ego Bogarda, gdzie również wyraża preferencję dla ogólnego interfejsu repozytorium. Zazwyczaj śledzę to za pomocą ogólnej klasy bazowej repozytorium, która implementuje ten interfejs; w ten sposób, muszę tylko wdrożyć rzeczy, które są różne dla każdej jednostki domeny.

0

Zwykle używam ogólnego repozytorium ze składem zamiast dziedziczenia. To daje mi korzyść w postaci ogólnej implementacji, z kontrolą której metody można wyeksponować.

coś takiego:

public Interface IRepository<T>{ 
    List<T> GetAll(); 
    void Create(T p); 
    void Update(T p); 
} 


public interface IProductRepository { 
    //Extension methods if needed 
    List<Product> GetProductsByCustomerID(); 
    List<T> GetAll(); 
    void Create(T p); 
    //Let assume here you should not be able to update the products 
} 

public ProductRepository : IProductRepository { 
    private IRepository _repository; 

    public ProductRepository(IRepository repository) { 
     this._repository = repository; 
    } 

     List<T> GetAll() 
     { 
      _repository.GetAll(); 
     } 

     void Create(T p) 
     { 
      _repository.Create(p); 
     } 

     List<Product> GetProductsByCustomerID() 
     { 
      //..implementation goes here 
     } 
} 
0

Repozytorium wzór jest jednym z najczęściej używanych wzór w rozwoju oprogramowania. Jest wiele postów, które można oznaczyć jako odpowiedź na twoje pytanie. Coś, co chciałbym podkreślić, to fakt, że dobre wdrożenie repozytorium zostanie poprawione, jeśli użyjesz IoC (Autofac, Windsor, itp.). Gram już dawno z niektórymi frameworkami opartymi o ADO.NET (LinqToSql, EF) i NHibernate. Zawsze możesz korzystać z ogólnej implementacji, jeśli korzystasz z IoC. Możesz definiować interfejsy dla konkretnych repozytoriów i rozwiązywać je, gdy naprawdę potrzebujesz określonych działań.