请看需求原型:
请看代码:
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扩展代码里面。