这篇文章其实是大健康行业直销系统的番外篇,主要给大家讲讲如何在领域逻辑中,有效的处理业务逻辑条件判断的最佳实践问题。

大家都知道,聚合根、实体和值对象这些领域对象都自身处理自己的业务逻辑。在业务处理过程中,通常会有一些条件判断,当满足这些条件时,会进行不同的后续处理。在传统的实现中,可以通过If Else条件语句进行判断,但If Else语句在复杂领域中来检查是否满足一些业务条件存在以下的问题:

1.      无法很好的显示表达业务条件本身。

2.      无法对多个条件在不同需要的地方进行灵活的组合。

为了更好的组织业务逻辑中关于业务条件的判断,最佳实践方式是将业务条件拆分得足够细,并用语义化的方式表示。这样,在当前上下文中的领域对象就可以使用一个或多个业务条件的组合。

举个例子:酒店业务中,房间领域对象会处理预定房间的领域逻辑和退房的领域逻辑,在预定房间时,我们需要保证房间没有被其他人预定并且房间没有正在维护这两个业务条件同时满足;在退房时,我们需要保证房间里没有物品损坏或已经进行了损坏赔偿这两个业务条件中的任意一个。

要实现上述的需求,我们可以分别作出4个业务条件规则,然后在界限上下文任意要使用的地方进行灵活的组合。

1.      为了达到上述目的,我们首先要开发出业务条件的接口与条件的组合方式定义。

public interface ISpecification<T>
{
bool IsSatisfied(T entity);
}

该规约接口就定义了一个方法,传入某个领域对象,判断是否满足条件。

public class AndSpecification<T> : ISpecification<T>
{
private ISpecification<T> left;
private ISpecification<T> right;
public AndSpecification(ISpecification<T> left,ISpecification<T> right)
{
this.left = left;
this.right = right;
}
public bool IsSatisfied(T entity)
{
return this.left.IsSatisfied(entity)
&& this.right.IsSatisfied(entity);
}
}

该类实现了两个业务条件的与关系。

public class OrSpecification<T> : ISpecification<T>
{
private ISpecification<T> left;
private ISpecification<T> right;
public OrSpecification(ISpecification<T> left, ISpecification<T> right)
{
this.left = left;
this.right = right;
}
public bool IsSatisfied(T entity)
{
return this.left.IsSatisfied(entity)
|| this.right.IsSatisfied(entity);
}
}

该类实现了两个业务条件的或关系。

2.      在房间业务界限上下文中,分别实现4个业务条件规则。

//房间没有被其他人预定业务条件判断
public class RoomIsNotConfirmedByOtherSpecification : ISpecification<Room>
{
public bool IsSatisfied(Room entity)
{
return !entity.OtherConfirmed;
}
}
//房间没有被正在维护业务条件判断
public class RoomIsNotMaintenanceSpecification : ISpecification<Room>
{
public bool IsSatisfied(Room entity)
{
return !entity.Maintenancing;
}
}
//房间没有物品损坏条件判断
public class RoomIsNotAnythingBrokenSpecification : ISpecification<Room>
{
public bool IsSatisfied(Room entity)
{
return !entity.AnythingBroken;
}
}
//房间没有物品损坏条件判断
public class RoomHasBeenBrokenCompensateSpecification : ISpecification<Room>
{
public bool IsSatisfied(Room entity)
{
return entity.HasBeenCompensated;
}
}

3.      在房间领域对象的预定房间与退房的领域逻辑中,组合使用上述4个条件规则

//预定房间
public Room Reservation()
{
var roomisnotconfirmedspec = new RoomIsNotConfirmedByOtherSpecification();
var roomisnotmaintenancespec = new RoomIsNotMaintenanceSpecification();
var researvationrulespec = new AndSpecification<Room>(roomisnotconfirmedspec, roomisnotconfirmedspec);
if (researvationrulespec)
{
//进行后续业务处理
}
return this;
} //退房
public Room CheckOut()
{
var roomisnotanythingbrokenspec = new RoomIsNotAnythingBrokenSpecification();
var roomhasbeenbrokenspec = new RoomHasBeenBrokenCompensateSpecification();
var checkrulespec = new OrSpecification<Room>(roomisnotanythingbrokenspec, roomhasbeenbrokenspec);
if (checkrulespec)
{
//进行后续业务处理
}
return this;
}

当然如果要任意组合多个与、或业务条件,需要在规约上实现Or、And方法来形成链式调用,具体怎么实现?有了上面的思路,自己写代码试试吧。

QQ讨论群:309287205

DDD实战进阶视频请关注微信公众号:

DDD实战进阶第一波(八):开发一般业务的大健康行业直销系统(业务逻辑条件判断最佳实践)的更多相关文章

  1. DDD实战进阶第一波(一):开发一般业务的大健康行业直销系统(概述)

    本系列文章 DDD实战进阶第一波(一):开发一般业务的大健康行业直销系统(概述) DDD实战进阶第一波(二):开发一般业务的大健康行业直销系统(搭建支持DDD的轻量级框架一) 近年来,关于如何开发基于 ...

  2. DDD实战进阶第一波(二):开发一般业务的大健康行业直销系统(搭建支持DDD的轻量级框架一)

    要实现软件设计.软件开发在一个统一的思想.统一的节奏下进行,就应该有一个轻量级的框架对开发过程与代码编写做一定的约束. 虽然DDD是一个软件开发的方法,而不是具体的技术或框架,但拥有一个轻量级的框架仍 ...

  3. DDD实战进阶第一波(三):开发一般业务的大健康行业直销系统(搭建支持DDD的轻量级框架二)

    了解了DDD的好处与基本的核心组件后,我们先不急着进入支持DDD思想的轻量级框架开发,也不急于直销系统需求分析和具体代码实现,我们还少一块, 那就是经典DDD的架构,只有了解了经典DDD的架构,你才能 ...

  4. DDD实战进阶第一波(五):开发一般业务的大健康行业直销系统(实现产品上下文领域层)

    从这篇文章开始,我们根据前面的DDD理论与DDD框架的约束,正式进入直销系统案例的开发. 本篇文章主要讲产品上下文中的领域层的主要实现,先简单讲下业务方面的需求:产品SPU与产品SKU,产品SPU主要 ...

  5. DDD实战进阶第一波(十五):开发一般业务的大健康行业直销系统(总结篇)

    前面我们花了14篇的文章来给大家介绍经典DDD的概念.架构和实践.这篇文章我们来做一个完整的总结,另外生成一个Api接口文档. 一.DDD解决传统的开发的几大问题: 没有描述需求的设计模型:而是直接通 ...

  6. DDD实战进阶第一波(六):开发一般业务的大健康行业直销系统(实现产品上下文仓储与应用服务层)

    前一篇文章我们完成了产品上下文的领域层,我们已经有了关于产品方面的简单领域逻辑,我们接着来实现产品上下文关于仓储持久化与应用层的用例如何来协调 领域逻辑与仓储持久化. 首先大家需要明确的是,产品上下文 ...

  7. DDD实战进阶第一波(十二):开发一般业务的大健康行业直销系统(订单上下文POCO模型)

    在本系列前面的文章中,我们主要讨论了产品上下文与经销商上下文相关的实现,大家对DDD的方法与架构已经有了初步的了解. 但是在这两个界限上下文中,业务逻辑很简单,也没有用到更多的值对象的内容.从这篇文章 ...

  8. DDD实战进阶第一波(四):开发一般业务的大健康行业直销系统(搭建支持DDD的轻量级框架三)

    上一篇文章我们讲了经典DDD架构对比传统三层架构的优势,以及经典DDD架构每一层的职责后,本篇文章将介绍基础结构层中支持DDD的轻量级框架的主要代码. 这里需要说明的是,DDD轻量级框架能够体现DDD ...

  9. DDD实战进阶第一波(九):开发一般业务的大健康行业直销系统(实现经销商上下文仓储与领域逻辑)

    上篇文章主要讲述了经销商上下文的需求与POCO对象,这篇文章主要讲述该界限上下文的仓储与领域逻辑的实现. 关于界限上下文与EF Core数据访问上下文参考产品上下文相应的实现,这里不再累述. 因为在经 ...

随机推荐

  1. Docker学习笔记 - Docker容器与外部网络的连接

    学习目的: ip_forward 包过滤防护墙 iptables 允许端口映射访问 限制ip访问容器 1.ip_forward 控制系统是否会转发流量 检查linux系统转发是否开启命令:sysctl ...

  2. python之路——初识函数

    阅读目录 为什么要用函数 函数的定义与调用 函数的返回值 函数的参数 本章小结 返回顶部 为什么要用函数 现在python届发生了一个大事件,len方法突然不能直接用了... 然后现在有一个需求,让你 ...

  3. Java 高级开发必修知识---反射

    Class类的使用 1) 在面向对象的世界里,万事万物皆对象 A. Java语言中,普通数据类型,静态成员不是对象,其他皆对象 B. 每一个类也是对象 C. 类是java.lang.Class类的实例 ...

  4. 道可道,非常道——详解promise

    promise 出来已久,以前一直使用,没有仔细剖析原理,最近在复习es6的知识,写一下自己对于promise的理解. promise是es6的一种异步编程解决方案,避免频繁的回调函数,增强代码的可阅 ...

  5. sort()与sorted()区分开

    列表的排序方法是sort 可用list.sort() sorted()是BIF不能用list.sorted() 引发的异常AttributeError: 'list' object has no at ...

  6. python判断素数的方法

    #运用python的数学函数 import math def isPrime(n): if n <= 1: return False for i in range(2, int(math.sqr ...

  7. Oracle数据库(3-7)

    显式游标使用主要有四个步骤: 声明/定义游标打开游标读取数据关闭游标 CASE 条件表达式 WHEN 条件表达式结果1 THEN 语句1 WHEN 条件表达式结果2 THEN 语句2 ...... W ...

  8. 前端开发必备之Chrome开发者工具(下篇)

    本文介绍的 Chrome 开发者工具基于 Chrome 65版本,如果你的 Chrome 开发者工具没有下文提到的那些内容,请检查下 Chrome 的版本 本文是 前端开发必备之Chrome开发者工具 ...

  9. 如何在Shell读取文件并赋值

    sys_info=$(cat /usr/local/sysconfig.txt)var=`echo   $sys_info   |   awk   -F ', '   '{print   $0} '  ...

  10. 【Python3.6+Django2.0+Xadmin2.0系列教程一】环境搭建及项目创建

    由于工作需要,接触了大半年时间的Django+xadmin框架,一直没空对这块对进行相关的梳理.最近在同事的怂恿下,就在这分享下笔者的学习及工作经验吧. 好了,话不多说,下面开始进入正题: 环境需求: ...