zoukankan      html  css  js  c++  java
  • EF架构~引入规约(Specification)模式,让程序扩展性更强

    回到目录

    规约(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层)

    DAL层

    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层去实现

    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,呵呵!

    回到目录

  • 相关阅读:
    SPOJ SAMER08A
    SPOJ TRAFFICN
    CS Academy Set Subtraction
    CS Academy Bad Triplet
    CF Round 432 C. Five Dimensional Points
    CF Round 432 B. Arpa and an exam about geometry
    SPOJ INVCNT
    CS Academy Palindromic Tree
    身体训练
    简单瞎搞题
  • 原文地址:https://www.cnblogs.com/lori/p/3146385.html
Copyright © 2011-2022 走看看