1.事务脚本
使用过程来组织业务逻辑,每个过程处理来自表现层的单个请求。
大多数业务应用都可以被看做是一系列的事务。一个事务可能将某种信息看做是以特定方式组织的,然后另一事务则会改变它。在客户系统和服务器系统之间的每次
交互都包含一定数量的逻辑。
事务脚本将所有这些逻辑组织成单个过程,在过程中直接调用数据库,或者只通过一个简单的数据库封装器。每个事务都有自己的事务脚本,尽管事务间的公共子任务可以
被分解成多个子程序。
1.运行机制
使用事务脚本,领域逻辑主要通过系统所执行的事务来组织。
可以将两种方法来把事务脚本组织成类。最常用的方法是将数个事务脚本放在一个类中,每个类围绕一个主题将相关的事务脚本组织在一起。另外一种方法则是每个事务
脚本对应一个类,此时需要使用命令模式。这种情况下应定义一个所有命令的父类,在父类中声明事务脚本逻辑适合的执行方法。将事务脚本组织成类的优点在于:允许你
运行时以对象的方式来控制脚本类的实例。当然,在许多语言中你可以不使用类而使用全局函数。但是,你通常会发现实例化新的对象有助于解决与线程相关的问题,因为
它比较容易实现数据隔离。
2.使用时机
事务脚本胜在简单。谨慎提取公共子程序可以避免很多问题,但更复杂的业务领域则需要建立领域模型。
2.领域模型
合并了行为和数据的领域的对象模型。领域模型创建了一张由互联对象组成的网,其中的每一个对象都代表某个有意义的个体。
1.运行机制
在应用程序中使用领域模型需要建立一个完整的由对象组成的层,来对目标业务领域建模。你会发现其中有的对象模拟业务活动中的数据,有的对象捕捉业务使用的规则。
数据和处理一般整合在一起,从而使得数据和数据之上的操作紧密聚合。
领域模型混合数据和处理过程,拥有多值属性和复杂的关联网,并且使用继承。
因此,领域模型衍生出两种风格。简单领域模型看起来与数据库设计很相似,这种设计中几乎每一个数据库表都与一个领域对象对应。而复杂领域模型则与数据库设计不同,
它使用继承,策略和其他设计模式,是一张由互联的细粒度对象组成的复杂网络。简单领域模型可以使用活动记录,而复杂领域模型需要使用数据映射器。
使用领域逻辑的一个常见问题是领域对象过于臃肿。
领域模型应当使用细粒度的对象,这些对象应有细粒度的接口。
2.使用时机
通常领域模型中经常能看到:多个类如何交互来完成即使很简单的任务。这也正是引起抱怨的原因 --- 在阅读面向对象的程序时,你得花费许多时间在一个个类之间跳转,
以找出它们之间是如何交互的。
在面向对象技术中,通过从一个对象到另外一个对象的连续传递可以把行为传给最有资格处理的对象,它同时也消除了许多条件判断行为。
3.表模块
处理某一数据库表或视图中所有行的业务逻辑的一个实例。
面向对象的关键思想之一是将数据与该数据操作的行为绑定在一起。传统的面向对象方法基于拥有标识符的对象,就像领域模型所使用的那样。
最常见的表模块例子是对数据库中的每一个表使用一个表模块。表模块可以是一个实例,也可以是一个静态方法的集合。
4.服务层
通过一个服务层来定义应用程序边界,在服务层中建立一组可用的操作集合,并在每个操作内部协调应用程序的响应。
企业级应用通常需要提供不同种类的接口来访问内部存储的数据和所实现的逻辑。
服务层定义了应用的边界和从接口客户层角度所能看到的可用操作集。它封装了应用的业务逻辑,事务控制及其操作实现中的响应协调。
1.运行机制
1.业务逻辑的种类
像事务脚本和领域模型一样,服务层是一种组织业务逻辑的模式。将业务逻辑分成两类:"领域逻辑"和"应用逻辑"。前者只与问题有关,如计算合同收入确认的策略等,
而后者与应用的职责有关,如关于收入确认计算的相关事宜,通知合同管理者,集成系统等。应用逻辑有时被称为"工作流逻辑"。
在避免领域逻辑的重复及利用经典模式来管理复杂性方面,领域逻辑优于事务脚本。但是将应用逻辑置于纯粹的领域对象类中也会带来一些不良后果。首先,如果在领域
对象类中实现了针对具体应用的逻辑,或者依赖于针对具体应用的软件包,则会降低该类在应用之间的的可重用性。其次,如果将来需要在如工作流工具之类的软件中重现
应用程序逻辑,则将两种逻辑混杂在同一个类中会使得这一工作比较困难。基于这些理由,服务层把每种业务逻辑分解成为一个单独的层,从而在获得分层的常规收益同时,
使得纯粹的领域对象类可以在不同应用之间更好的被重用。
2.实现方法
领域外观方法和操作脚本方法是两种基本的实现方法。在领域外观方法中,服务层以领域模型之上的瘦外观集合方式实现。负责实现外观的类不包含任务业务逻辑,所有的
业务逻辑均由领域模型实现。瘦外观建立了客户层与应用程序交互的边界和操作集,这正显示出服务层的定义特征。
在操作脚本方法中,服务层是由一组相对复杂的类组成,这些类直接实现应用逻辑,但将领域逻辑委托给封装好的领域对象类。服务层客户所能使用的操作以脚本的方式实现,
数个脚本组成一个类,一个类定义与某一个主题相关的逻辑。每一个类组成一个应用程序'服务',通常服务类型的名字都为'xx服务'。服务层由这些应用程序服务类组成,它们
之上应当扩展出一个抽象了职责和公共行为的层超类型。
3.是否远程
由于服务层类的接口声明一组应用操作来与客户层连接,因此从定义上说:服务层类的接口是粗粒度的。所以说,就接口粒度而言,服务层很适合于远程调用。但是远程调用的
代价在于对对象分布性的处理。
我的建议是,开始时仅设计一个本地调用的服务层,其方法标记中仅处理领域对象。当你需要远程调用功能时,再通过在服务层之上增加一个远程外观来实现,或者让你的服务层
对象实现远程接口。
4.识别服务与操作
识别出服务层边界上应提供的操作十分简单。它们由服务层客户的需求决定,其中最重要的通常是用户界面。由于用户界面是为支持执行者与应用程序交互的用例而设计的,因此
标识服务层操作的起点应该是用例模型和应用程序的用户界面设计。
服务层的优点在于,它定义了一个公共的应用操作结合,这一集合可以被各种客户使用,而且服务层在每个操作中都会协调应用的响应。响应可能涉及某些需要在多个事务性资源
之间进行原子化处理的应用逻辑。因此,在业务逻辑中有多种客户的应用中,或者其用例中的复杂响应涉及多个事务性资源时,即使不是分布式架构,使用一个容器管理事务的服务层
仍是很有必要的。
比较容易回答的是什么时候不应该使用服务层。如果你的业务逻辑只有一种客户 --- 如用户界面,或者用例响应并不涉及多个事务性资源,就可能不需要使用服务层。此时,你的
页面控制器可以人工控制事务并随时协调所需的响应,可能直接将这些响应发给数据源层。
但是如果你能预见到第二个客户,或用例响应中的第二个事务性资源,则有必要再一开始时就设计一个服务层。