請看需求原型:
請看代碼:
1 namespace Demo.Services 2 { 3 public class OrderService : IOrderService 4 { 5 public PagedResult<OrderDto> Search(OrderSearchCriteria criteria, PageRequest page) 6 { 7 PagedResult<OrderDto> result; 8 using (var db = new DemoDbContext()) 9 { 10 result = db.Orders 11 .WhereByDealerId(criteria.DealerId) 12 .WhereByStatus(criteria.Status) 13 .WhereByProductType(criteria.ProductTypeId) 14 .WhereByNumber(criteria.OrderNumber) 15 .WhereByKeyword(criteria.Keyword) 16 .WhereByFromDate(criteria.FromDate) 17 .WhereByToDate(criteria.ToDate) 18 .WhereByFromCost(criteria.FromCost) 19 .WhereByToCost(criteria.ToCost) 20 .ToOrderDtos() 21 .PageTo(page); 22 } 23 return result.BuildDealerInfo() 24 .BuildProductInfo() 25 .BuildCustomerInfo() 26 .BuildReceiver(); 27 } 28 } 29 }
這段代碼可讀性高、可擴展性強,更容易寫單元測試。對於所有的列表查詢類代碼都應該寫成這樣,據我現在的知識,這已是最好的代碼了。
對於很多開發人員來講,這樣一個頁面,寫一個查詢方法寫一兩百行出來,到處是注釋,到處看不懂。這樣的開發人員很多,包括很多年經驗的。
我之前分享過關於c#擴展方法的極致用法,很多人嗤之以鼻、不屑一顧,認為僅僅是“語法糖”。
上面的代碼中,用到的“伎倆”是非常簡單的,但是效果是很明顯的。所以,管他語法糖不語法糖,只要是能幫助我們寫出漂亮的代碼,就堅決去寫。
當然,從原理上講,上面這段代碼是完全符合面向對象思想的。你可以仔細品味便會發現面向對象的魅力所在。
最后再說下上面的代碼在架構上怎么安排:
- WhereBy過濾的代碼放到實體類擴展里面,跟實體類(domain層)的定義放在同一個程序集,挨着實體類定義。上面的例子中,放到OrderExtensions類里面。
- DTO類定義在service層,非domain層。ToOrderDtos()放在dto擴展類里面。上面的例子中,放到OrderDtoExtensions類里面。
- PageTo屬於IQueryable<T>的擴展,放到infrastructure層。
- Build放到service層,DTO擴展代碼里面。