在DDD领域构架系统中,为了将领域模型从领域逻辑层中和数据映射层之间解耦出来,我们引用到了Repository模式,属于属于泛型编程中一个比较常用的模式,尤其应用到MVC构架中更为常见,我们来简单的介绍几个概念:
1、在《领域驱动设计:软件核心复杂性应对之道》,将Repository翻译为仓储,说明为:
一种用来封装存储,读取和查找行为的机制,它模拟了一个对象集合。
2、在《企业构架模式》中,译者对其翻译为:资源库,说明如下:
通过用来访问领域对象的一个类似集合的接口,在领域与数据映射层之间进行协调
下面通过一个案例才详细说明该解耦过程
一、新建应用程序,添加Linq To Sql,新建两个领域模型,用会员模型(Dinner)和会议模型(RSVP),很明显这里应该是一对多的关系,也即是说一张会议会有很多人来参与。
二、 我们将对实体的公共操作部分,提取为IRepository接口,比如常见的也就是增删改查等方法。如下代码:
public interface IRepository<T> where T : class
{
//改变模型中没有更新,里面的Save就取代更新功能
IEnumerable<T> FindAll(Func<T, bool> exp);
void Add(T entity);
void Delete(T entity);
void Save();
}
三,下面我们实现一个泛型的类来具体实现上面的接口的方法。也就是实现领域模型的操作:
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 IDinnerRepository: IRepository<Dinner>
{
IList<Dinner> GetAllByDinnerId(int id);
}
4、最后该实体的Repository类实现,注意要同时继承它的接口约束和Repository<T>类,如下:
public class DinnerRepository : Repository<Dinner>, IDinnerRepository
{
public DinnerRepository(DataContext dc)
: base(dc)
{ }
public IList<Dinner> GetAllByBookId(int id)
{
var listDinner = from c in context.GetTable<Dinner>()
where c.DinnerID == id
select c;
return listDinner.ToList();
}
}
基本思路就这样了,在我们使用的时候,需要几个扩展类,在定义领域模型责任接口,在实现领域对象业务领域的扩展,实现类就要同时继承基类和约束接口了。