zoukankan      html  css  js  c++  java
  • DDD~领域服务的规约模式

    回到目录

    规 约(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,呵呵!

    回到目录

  • 相关阅读:
    HDU 3681 Prison Break 越狱(状压DP,变形)
    POJ 2411 Mondriaan's Dream (状压DP,骨牌覆盖,经典)
    ZOJ 3471 Most Powerful (状压DP,经典)
    POJ 2288 Islands and Bridges (状压DP,变形)
    HDU 3001 Travelling (状压DP,3进制)
    POJ 3311 Hie with the Pie (状压DP)
    POJ 1185 炮兵阵地 (状压DP,轮廓线DP)
    FZU 2204 7
    POJ 3254 Corn Fields (状压DP,轮廓线DP)
    ZOJ 3494 BCD Code (数位DP,AC自动机)
  • 原文地址:https://www.cnblogs.com/lori/p/3472793.html
Copyright © 2011-2022 走看看