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

    回到目录

  • 相关阅读:
    HanLP《自然语言处理入门》笔记--5.感知机模型与序列标注
    Netty系列-netty的Future 和 Promise
    Netty系列-netty的初体验
    CentOS7 源码编译安装Nginx
    linux 源码编译安装MySQL
    Linux CentOS7
    Linux CentOS7 搭建ntp时间同步服务器
    CentOS7-7搭建ftp服务器
    CentOS7-7 搭建dhcp服务器
    python批量扫描脚本
  • 原文地址:https://www.cnblogs.com/lori/p/3146385.html
Copyright © 2020-2023  润新知