组织领域逻辑
领域逻辑的组织可以分为三种主要的模式:
1.事务脚本
2.领域模型
3.表模块
保存领域逻辑最简单的方法是使用事务脚本。简单的说,事务脚本是这样一个过程:从表示层获取输入,进行校验和计算处理,将数据存储到数据库中以及调用其他
系统的操作等。然后,该过程将更多的数据返回给表示层,中间可能要进行大量的计算来组织和整理返回值。基本的组织方式是让每个过程对应用户可能做的一个动作。
所以,我们可以将这一模式想象成一个动作或者业务事务的脚步。该脚步不必一定是单个的内嵌过程,还可以分离成不同的子例程,这些子例程可以在不同的事务脚本
之间共享。但是,每一个动作还是由一个过程来驱动。
优点:
1.它是一个大多数开发者都能理解的简单过程模型
2.它能够与一个使用行数据入口或表数据入口的简单数据源层很好的协作。
3.设定事务边界的方法显而易见:一个事务开始于脚本的打开,终于脚本的关闭。很容易用工具在幕后设定事务边界。
缺点:当领域逻辑的复杂性增加时这些缺点就会凸显。当若干个事务需要做相似的动作时,通常使多个脚本中包含某些相同的代码。通过将这些代码提取出来组成公共
的子例程可以部分消除这种情况,但在许多时候,消除副本仍比较棘手,而检测副本则更为艰难。
当然,复杂逻辑情况的处理必然要引入对象,解决前述问题的面向对象方法就是使用领域模型。我们建立一个应用领域的模型,至少在开始的时候主要围绕领域中的名词
来组织。例如,一个租赁系统会有租赁,资产等。进行校验和计算的逻辑会置于领域模型中,因此发货对象可能会包含计算一次运行费用的逻辑。可能还有其他历程也完成
计算账单的功能,但它实际上是调用领域模型中的已有方法来实现的。
用领域模型而不是事务脚本正式面向对象的程序员所极力鼓吹的'理论体系转换'的精髓。在领域模型中,不再是由一个过程来控制用户的某一动作的逻辑,而是由每一个
对象都承担一部分相关逻辑。
领域模型的价值在于你一旦掌握了它,就可以运用许多现成的技术来比较好的组织日趋复杂的领域逻辑。例如,当增加新的收入确认算法的时候,只需增加相应的新策略
对象即可。而使用事务脚本则需要在脚本的判断逻辑中增加许多新的条件。
领域模型的开销来自使用上的复杂性和数据源层的复杂性。还需要面对将领域模型映射到数据库的问题。运用领域模型越充分,当你将它映射到关系数据库时就越复杂(
通常使用数据映射器)。
第三种组织领域逻辑的模式是表模块。这一模式看起来跟领域模型很相似,关键的区别在于领域模型对数据库中的每一个合同都有一个相应的合同类的实例,而表模块
只有一个公共的合同类实例。表模块的设计与记录集一起工作,因此,在一个用来处理合同的表模块中,客户需要首先对数据库进行查询以生成一个记录集,然后以记录
集为参数创建一个合同对象。客户可以调用合同对象的方法来完成各种操作,如果客户要对某个指定的合同进行操作,它就必须在调用方法时附加该合同的ID。
在许多方面,表模块是事务脚本和领域模型的一个中间地带。它围绕表而非直接绕过过程来组织领域逻辑,提供了更多的结构,而且更容易发现和移除冗余代码。但是
你无法应用许多在领域模型中可以使用的组织细粒度逻辑结构的技术,例如继承,策略和其他面向对象的设计模式。
表模式最大的优点在于其与软件架构中已有的部分的衔接。许多gui环境在设计时都假定其将与sql查询的返回结果协同工作,这些结果是以记录集的方式组织的。表模块
也工作在记录集之上,因此你可以很容易的对数据库进行一次查询,然后在表模块内对返回结果进行操作,再把操作完成后的数据传给GUI显示。你也可以在将用户界面中
修改的数据回传到数据库时,使用表模块来完成计算和校验。
抉择:
那这3种模式如何选择呢?很大程度上取决于领域逻辑的复杂度。当领域逻辑很简单时,领域模型并不合适,因为要透彻理解这一模式需要很大的代价,而且数据源层的复杂性
也会在开发中增加很多工足量。然后,当领域逻辑的复杂度增加时,除离你关于模型意外的其他方法就都不适用了,因为它们增加的新功能的困难程度随着系统复杂度的增加而呈
指数增长。
是否使用表模块很大程度上取决于环境对通用记录集结构的支持。
服务层:
处理领域逻辑的常见方法是将领域层再细分为2层。服务层独立出来,置于底层的领域模型或表模块之上。通常只有使用领域模型或表模块时才会这样细分,因为仅仅使用事务脚本
的领域层并不复杂,没有必要再单独设置服务层。表现逻辑与领域层的交互完全通过服务层,就好像应用程序的API一样。
在提供一个清晰的api的同时,服务层也是放置事务控制和安全等功能的好场所。这样做可以使你获得一个简单的,包含了服务层所有的方法并描述了其他事务和安全特性的模型。
如果设置了服务层,在其中置入行为的多少是一个至关重要的决定。最小化的情况下,服务层只是一个外观,实际所有的行为都在下层的对象中,服务层所做的只是将上层调用传递
到更底层。在这种情况下,服务层提供一个更易于使用的api,因为它的方法通常根据用例来组织。此时,它也提供一个很方便的切入点,用来增加事务封装和安全检查等功能。
另外一极端是将大多数业务逻辑都以事务脚本的形式置于服务层中。下次的领域对象变得极为简单。如果下层是领域模型,则其中的对象与数据库一一对应,因而此时你就可以使用
诸如活动记录等较简单的数据源层。
以上二者的折中是一个行为的混合体:控制器---实体风格。此处要点在于:将单个事务或用例所有的逻辑置于事务脚本中,它们通常被称为控制器或服务。有许多不同的控制器,
如模型---视图---控制器中的输入控制器和我们稍后接触的应用控制器。我们在此用'用例控制器'。可供多个用例调用的行为访问那些被称为实体的领域对象。
虽然控制器---实体方法很常用,但与事务脚本一样,用例控制器容易产生代码副本。
如果需要,尽可能使用最小化的服务层。