近来发现很多ASP.NET MVC的例子中都使用了Repository模式,比如Oxite,ScottGu最近发布的免费的ASP.NET MVC教程都使用了该模式。就简单看了下。
在《企业架构模式》中,译者将Repository翻译为资源库。给出如下说明:
通过用来访问领域对象的一个类似集合的接口,在领域与数据映射层之间进行协调。
在《领域驱动设计:软件核心复杂性应对之道》中,译者将Repository翻译为仓储,给出如下说明:
一种用来封装存储,读取和查找行为的机制,它模拟了一个对象集合。
使用该模式的最大好处就是将领域模型从客户代码和数据映射层之间解耦出来。
我们来看下在LinqToSQL中如何应用该模式。
1. 我们将对实体的公共操作部分,提取为IRepository接口,比如常见的增加,删除等方法。如下代码:
interface IRepository<T> where T : class { IEnumerable<T> FindAll(Func<T, bool> exp); void Add(T entity); void Delete(T entity); void Save(); }
2.下面我们实现一个泛型的类来具体实现上面的接口的方法。
public class Repository<T> : IRepository<T> where T : class { public DataContext context; public Repository(DataContext context) { this.context = context; } public IEnumerable<T> FindAll(Func<T, bool> exp) { return context.GetTable<T>().Where(exp); } public void Add(T entity) { context.GetTable<T>().InsertOnSubmit(entity); } public void Delete(T entity) { context.GetTable<T>().DeleteOnSubmit(entity); } public void Save() { context.SubmitChanges(); } }
3.上面我们实现是每个实体公共的操作,但是实际中每个实体都有符合自己业务的逻辑。我们单独定义另外一个接口,例如:
interface IBookRepository : IRepository<Book> { IList<Book> GetAllByBookId(int id); }
4.最后该实体的Repository类实现如下:
public class BookRepository : Repository<Book>, IBookRepository { public BookRepository(DataContext dc) : base(dc) { } public IList<Book> GetAllByBookId(int id) { var listbook = from c in context.GetTable<Book>() where c.BookId == id select c; return listbook.ToList(); } }
上面只是为大家提供了一个最基本使用框架。
因此Repository接口还是应该单独针对每个Eneity类来定义,比如User
interface IUserRepository
{
IEnumerable<User> FindAllUser();
void Add(User user);
//void Delete(User user); //User不应该能被删除,因此接口中没有此方法
string GetPassword(int userId);//User特有的操作
}
而泛型的Repository<T>类仍然用来减少重复代码,只是不能被UserRepository类直接继承,因为这样 Delete方法将侵入User类,所以改为在UserRepository中组合一个Repository<T>,将开放给domain可 见且又能使用泛型重用的功能委托给这个Repository<T>,
public class UserRepository : IUserRepository
{
private DataContext context;
private Repository<User> internalGenericRepository;
public BookRepository(DataContext dc)
{
this.context = dc;
this.internalGenericRepository = new Repository<User>(dc);
}
public void Add(User user);
{
this.internalGenericRepository.Add(user);
}
public string GetPassword(int userId)
{
string password = context.User.where(u=>u.id==userId).select(u=>u.password);
}
}
也就是说泛型接口->泛型类->具体接口继承泛型接口->具体类继承具体接口和泛型类的方式变为
具体接口->具体类继承具体接口+组合泛型类
Repository是DDD中的概念,强调Repository是受Domain驱动的,Repository中定义的功能要体现Domain的意图和约束,而Dal更纯粹的就是提供数据访问的功能,并不严格受限于Business层.
就拿上面写的User的例子来说,使用Repository,隐含着一种意图倾向,就是Domain需要什么我才提供什么,不该提供的功能就不要提供,一切都是以Domain的需求为核心;
而使用Dal,其意图倾向在于我Dal层能使用的数据库访问操作提供给Business层,你Business要用哪个自己选.换一个Business也可以用我这个Dal,一切是以我Dal能提供什么操作为核心.