2010-04-21 59 views
32

我試圖找出存儲庫模式的正確定義。存儲庫模式方法的標準化

我原來的理解是這樣的(非常簡單化了),從數據

  • 獨立您的Business Objects對象在數據訪問層
  • 標準化的接入方式。

我真的看到了2種不同的實現方式,網上沒有正式的例子,我看到的那些東西都藏在書本里。

實現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(); 
} 

實現2:

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

注意到的第一件是通用的獲取/更新/ GETALL等,二是更多的東西我會將「DAO」定義爲。

兩者都共享數據實體提取。我喜歡,但我可以做一個簡單的DAO相同。然而,第二件規範訪問操作我看到價值,如果實施該企業廣泛的人會很容易地掌握設定爲您的存儲庫訪問方法。

我錯誤地認爲數據訪問的標準化是這種模式的一個組成部分嗎?如果兩者都是正確的,那麼爲什麼會選擇執行實施2?

Rhino在實現1中有一篇很好的文章,當然MS有一個模糊的definition,實現2的一個例子是here

+0

對我來說_interface_是一個抽象,即與_implementation_相反。我們是在討論這裏的接口,還是在討論實現類? – MEMark 2013-10-12 14:38:25

回答

14

我第二次被oded引用的福勒報價。我想指出他說的是「收集-」,如「的界面。你如何實現像接口這樣的集合當然取決於你,但既不能也不應該試圖隱藏它代表遠程數據源的事實。因此它與內存集合有很大的不同,它不需要將更改刷新到遠程數據存儲。 ORM的更改跟蹤機制或您自己的解決方案決定了調用者的透明度。刪除通常需要顯式標記,插入是可發現的(通過可達性持久化),更新有時也需要顯式標記。將此與複合根的複雜依賴關係結合起來,你會發現這不是很像集合。

有沒有這樣的事情「的cannonical存儲庫實施」。

通用存儲庫基類的倡導者與喜歡單獨實現每個存儲庫的人之間不斷髮生爭鬥。雖然通用實現在簡單場景中很有吸引力,但您經常會發現它是一個非常泄漏的抽象。例如,某些聚合可能只能被軟刪除(可通過虛擬方法覆蓋進行調整),而其他可能根本不支持刪除操作。

確定您在決定採用哪條路線之前瞭解每種方法的含義。格雷格楊對通用知識庫的優點發表了一篇不錯的文章。

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

7

從馬丁福勒,Repository模式的定義中的「企業應用架構模式」是:在使用用於訪問域對象的集合狀界面域和數據映射層之間

介導。

所以,兩種方法都是正確的。

+0

我想整個「集合樣」是模糊的,我會爭辯說集合像意味着獲取/更新/刪除/等不是..但我假設你會爭辯相同的Get = GetProduct – Nix 2010-04-21 15:41:48

4

我一般存儲庫模式的忠實球迷,但我認爲你應該認真考慮不直接從接口繼承,因爲它可以成爲一個非常大的限制,特別是因爲通用接口多次的代碼是相同的是它可以在一個抽象基類中定義,你將不再能夠在一個類中擁有多於一個的通用存儲庫。

我建議讓你的IProductRepository實現者通過委託來訪問通用的IRepository<Product>,並通過構造函數注入,這樣你就可以編寫你可能有很多IRepositories的類,並以一種合理的方式將它們分組在單個接口之後。

我寫了一篇博客有關這個主題的同時明確引用NHibernate的這種模式可以適用於任何類型的存儲庫:Creating a common generic and extensible NHiberate Repository version 2

2

隨着.NET的LINQ引進的,通用的存儲庫模式變得更加容易實現:

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

要成爲儲存庫,它僅需要能夠訪問數據在底層存儲(由IQueryable容易地提供),並修改所包含的數據。

您可以爲基本接口提供擴展以提供更多特定於實體的行爲的掛鉤(例如,連接到基於SQL的存儲庫的存儲過程調用),但大多數操作可以通過簡單的接口完成。

1

除了您的通用倉庫接口(實施1)和你的角色特定的庫變化(實施2)你也可以考慮泛型方法庫:

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; 
} 

這第三個版本來自Jimmy Bogard的this blogpost,他在那裏也表達了對通用知識庫接口的偏好。 我通常使用實現此接口的通用存儲庫基類來實現此功能;這樣,我只需要爲每個域實體實現不同的內容。

0

我通常使用具有組合而不是繼承的通用資源庫。這給了我一個通用實現的優點,並控制要公開哪些方法。

事情是這樣的:

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

Repository模式是軟件開發中最常用的方式之一。很多帖子可以標記爲回答你的問題。 我喜歡強調的一點是,如果使用IoC(Autofac,Windsor等),好的存儲庫實現將得到改進。我很久以前就玩過一些基於ADO.NET的框架(LinqToSql,EF)和NHibernate。如果您使用IoC,則始終可以從通用實施中獲益。 您可以爲特定存儲庫定義接口並解決您何時需要某些特定操作。