規 約(Specification)模式:第一次看到這東西是在microsoft NLayer項目中,它是微軟對DDD的解說,就像petshop告訴了我們MVC如何使用一樣,這個規約模式最重要的作用是實現了查詢語句與查詢條件的 分離,查詢語句在底層是穩定的,不變的,而查詢條件是和具體業務,具體領域有關的,是易變的,如果我們為每一個領域的每一個新需求都寫一個新的方法,那就 會出現很多重復的代碼,不利于程序的最終擴展!
下面我們來看一個經典例子
一個IOrderRepository的接口,定義了一個訂單倉儲
Order_Info GetOrder_InfoById(int orderID); List<Order_Info> GetOrder_Info(DateTime from, DateTime to); List<Order_Info> GetOrder_InfoByUser(int userID);
代碼本身沒有任何問題,你只要去實現它就可以了,當一個新的需求到了之后,你的接口要被擴展(這是不被提倡的,一般我們會新建一個接口),然后修改
原來的實現類,去實現接口新的方法(違背了OCP原則),這種做法是大多部開發團隊所經歷了,我,一個普通的人,也經歷了,但當我知道DDD后,當我看完
microsoft Nlayer項目之后,我知道,我一定要改變這種局面,于是,代碼在規約模式的指導下,進行重構了,呵呵。
先看一下規約模式的類關系圖
下面是我對原來結構的修改(由于原程序是三層架構,所以我就不改變原有架構了,只是對代碼進行重構,DAL層,BLL層,WEB層)
基礎設施層
IRepository倉儲接口如下,怎么去實現就不放了,呵呵
public interface IRepository<TEntity> where TEntity : class { /// <summary> /// 添加實體并提交到數據服務器 /// </summary> /// <param name="item">Item to add to repository</param> void Add(TEntity item); /// <summary> /// 移除實體并提交到數據服務器 /// 如果表存在約束,需要先刪除子表信息 /// </summary> /// <param name="item">Item to delete</param> void Remove(TEntity item); /// <summary> /// 修改實體并提交到數據服務器 /// </summary> /// <param name="item"></param> void Modify(TEntity item); /// <summary> /// 通過指定規約,得到實體對象 /// </summary> /// <param name="specification"></param> /// <returns></returns> TEntity GetEntity(ISpecification<TEntity> specification); /// <summary> /// 通用表達式樹,得到實體 /// </summary> /// <param name="predicate"></param> /// <returns></returns> TEntity GetEntity(Expression<Func<TEntity, bool>> predicate); /// <summary> /// Get all elements of type {T} in repository /// </summary> /// <returns>List of selected elements</returns> IQueryable<TEntity> GetEntities(); /// <summary> /// Get all elements of type {T} that matching a /// Specification <paramref name="specification"/> /// </summary> /// <param name="specification">Specification that result meet</param> /// <returns></returns> IQueryable<TEntity> GetEntities(ISpecification<TEntity> specification); /// <summary> /// 通用表達式樹,得到集合 /// </summary> /// <param name="predicate"></param> /// <returns></returns> IQueryable<TEntity> GetEntities(Expression<Func<TEntity, bool>> predicate); }
IOrderRepository接口如下
public interface IOrderRepository : Domain.Core.IRepository<Order_Info> { void InsertOrder(Order_Info entity); }
DAL底層為數據持久化層,它是非常穩定的,只提供最基本的表操作,具體業務如何組成,全放在BLL層去實現
領域層
這一層中定義具體業務的規約,并組成查詢方法及調用DAL層的具體方法(DAL層來接受從BLL層傳過來的ISpecification參數)
/// <summary> /// 根據下單日期得到訂單列表 /// </summary> public class OrderFromDateSpecification : Specification<Order_Info> { DateTime? _fromDate; DateTime? _toDate; public OrderFromDateSpecification(DateTime? fromDate, DateTime? toDate) { _fromDate = fromDate ?? DateTime.MinValue; _toDate = toDate ?? DateTime.MaxValue; } public override global::System.Linq.Expressions.Expression<Func<Order_Info, bool>> SatisfiedBy() { Specification<Order_Info> spec = new TrueSpecification<Order_Info>(); spec &= new DirectSpecification<Order_Info>(o => o.CreateDate >= _fromDate && o.CreateDate <= _toDate); return spec.SatisfiedBy(); } }
/// <summary> /// 通過用戶信息得到他的訂單列表 /// </summary> public class OrderFromUserSpecification : Specification<Order_Info> { int _userID = default(Int32); public OrderFromUserSpecification(int userID) { _userID = userID; } public override global::System.Linq.Expressions.Expression<Func<Order_Info, bool>> SatisfiedBy() { Specification<Order_Info> spec = new TrueSpecification<Order_Info>(); spec &= new DirectSpecification<Order_Info>(o => o.UserID == _userID); return spec.SatisfiedBy(); } }
業務層真實的查詢主體,只要在一個方法里寫就OK了,然后它非常穩定,如果以后還有其它查詢業務出來,直接添加一個查詢規約即可
/// <summary> /// 根據WEB層傳來及組件好的規約,返回集體 /// </summary> /// <param name="spec"></param> /// <returns></returns> public List<Order_Info> GetOrder_InfoBySpec(ISpecification<Order_Info> spec) { return _iOrderRepository.GetEntities(spec).ToList(); }
WEB層
Web層建立一個指定的規約,并為規約組件所需要的數據即可
public ActionResult List(int? userID) { ISpecification<Order_Info> spec = new OrderFromUserSpecification(userID ?? 0); var model = orderService.GetOrder_InfoBySpec(spec); return View(model); }
如果這時來了個新需要,使用用戶名進行查詢,你可以直接建立一個OrderFromUserNameSpecification的規約即可,而不需要修改OrderService,呵呵!
文章列表
留言列表