iT邦幫忙

0

甚麼是 Repository ?

甚麼是 Repository ?

這一天小明問我甚麼是Repository ?

很多應用程式都有資料存取的需求,大多數使用的都是關聯式資料庫 (RDBMS),
大多數的開發人員使用ODBC, DB-Library, ADO.NET, OLE DB 等不同的介面,
再搭配 SQL 指令來存取資料.

為了要整合這麼多種資料儲存類型,最好的方法就是將要儲存的物件抽取出來變成一個實體物件(Entity),
有了Entity 物件後,就可以試著傳遞Entity 資料到某個介面interface,以達到儲存或讀取Entity 的能力,
這個抽象化介面就是 Repository .

只要向資料儲存體Repository 存放資料或要讀取資料,如果資料儲存體換了,
只要抽換掉 Repository interface 的實作即可,
上層的服務完全不需要異動, 而這也是 Repository 最終的目的。

Repository 有很多種實作方法,有很多人用一個Repository 代表一個DB 裡面的 Table.
為了減少重複的程式碼, 也有人是以Generic 的方式,寫一種通用型的Repository , 如下示範通用型的IRepository

public interface IRepository<T>
{
    void Create(T entity);
    T Read(Expression<Func<T, bool>> predicate);
    void Update(T entity);
    void Delete(T entity);
    void SaveChanges();
}

如果我同時要用2 個Table 以上怎麼辦?有人就寫了IUnitOfWork 來做這件事情.
以下是 IUnitOfWork 程式碼,

public interface IUnitOfWork
{
    IGenericRepository<Customer> Customer { get; }
    IGenericRepository<Order> Order { get; }
    Task<int> SaveChangeAsync();
}

熟悉Entity Framework 的人, 可以發現這跟Entity Framework 架構一樣,
上述IUnitOfWork 程式碼可以呼應對應到下面的Entity Framework 程式碼

public MyDbContext : DbContext
{
   public DbSet<Customer> Customer { get; set; }
   public DbSet<Order> Order { get; set; }
}

在ORM / Entity Framework , 還沒那麼成熟的年代,
使用 Repository 模式的理由很充分,好處也明顯.

當 Entity Framework 和 NHibernate 已經提供了同樣, 甚至更多的功能, 我們還需要再多加一層 Repository 嗎?
網路上可以找到很多文章,介紹如何搭配 Entity Framework 來設計我們的 Repository.
所以「怎麼做」並不是問題,問題在於我們是否該這麼做?

假如你原本用Entity Framework 去存取SQL Server,
有一天你想改為Sqlite, 你也只需提供DB Provider , 外層的程式碼也不需要改動.
也能存取各種不同的資料庫.

拿掉Repository 之後,單元測試還是可以做,只要在資料庫存取方法提升到interface method,
仍然可以進行隔離測試.

其次,可抽換底層的資料存取元件當然很理想. 然而就算我們用Repository 把它包起來,難保不夠周密.
除了擔心開發時間成本效益,我也懷疑真實世界中有多少案子真的需要而且實際有「任意切換不同的儲存媒體」的需求.

至於Unit of Work,其實 EF 的 ObjectContext 和 DbContext 已經提供了類似的功能.
如果在ORM 之上再疊一層 Repository,會讓我們費好大功夫寫一堆看起來長得很像的程式碼,
增加程式的複雜性,卻得不到相對比例的好處.

就我的觀點而言,在不需要切換任意 實際儲存資料體 的情況下,比較小而單純的應用程式,
我不會使用Repository . 如果是比較大型或複雜的系統....嗯,
目前我是沒遇過同一套系統還需要切換不同種類的資料儲存媒體.


尚未有邦友留言

立即登入留言