我自己的一生

是你的,是我的,到底是谁的?

导航

设计应用程序和服务的组件

 

第一章描述了一个应用程序或者服务是如何别多样的组件合成的,每个组件执行不同类型的任务。无论特定的业务是什么,每个软件的解决方案都包含相似类型的组件。例如,许多应用程序都包含访问数据,封装业务规则,处理用户交互等等。识别出在分布式软件解决方案中的一般类型的组件,有益于有构造一个蓝本,用于应用程序或服务的设计。

 

本章内容

这章包含下面的章节:

l  组件类型

l  应用程序和服务的一般设计建议

l  设计表现层

l  设计业务层

l  设计数据层

 

组件类型

对大多数基于分层组件的业务解决方案进行检查,都会显露出数个一般组件类型。图2.1显示了一个全面的插图,其中包括这些组件。

 

注意:术语“组件”是指用于在全部解决方案的一块或者一部分场景中。这个包括已编译过的软件组件,如,Microsoft .NET 程序集,和其它软件工件,如,WEB页面和Microsoft BizTalk Server的编排架构。

 

虽然在图1.2中所列举的组件不是很完整,但我们在大部分分布式解决方案所发现的一般类型的软件组件,都在里面。这些组件类型会在这章以下部分进行深入的描述。

 

2.1 在零售范例场景中组件类型

 

在范型场景设计中,识别出的组件类型:

1.  用户界面(UI)组件。大部分解决方案需要提供一个和用户交互的方法。在零售应用程序例子中,一个WEB站点让客户可以浏览产品和提交订单,基于Microsoft Windows操作系统的应用程序让和可以电话沟通的销售代表进入订单数据。用户界面可以使用Windows FormsMicrosoft ASP.NET页面,控件或任何其它技术实现,你为可以呈现和格式化数据,从他们那里获得并验证数据。

2.  用户处理组件。在许多场景下,用户和系统的交互,是紧随一个可以预言的过程。例如,在零售应用程序中,你可以实现一个浏览产品的程序,用户选择一个产品种类,然后再选择的种类中选择一个产品查看产品明细。同样,当用户决定一个采购时,交互遵循一个可预知过程,这个过程从用户那里采集数据,在这个过程中,用户首先提供产品明细到采购中,然后,提供支付明细,在然后,进入交付明细。使用隔离的用户处理组件,可以对同步和编排这些用户交互过程的驱动有很大意义。处理流程和状态管理逻辑的这个方法不能硬编码在他们自己的用户界面元素中,相同的基本用户交互“引擎”可以被重用在多个用户界面上。

3.  业务工作流。通过用户处理,需要的数据被搜集后,这些数据被用在业务过程的执行。例如,产品、支付和交货明细被提交到零售应用程序之后,获取支付和安排交货的过程开始了。包括多个步骤的许多业务过程必须按照正确的顺序和编排执行。例如,零售系统需要计算订单的全部价值,验证信用卡明细,处理信用卡支付和安排货物交付。这个过程会花费一些不确定的时间来完成,执行被请求的任务和需要的数据一定要被管理起来。业务工作流定义和等同于长期运行,多步骤的业务过程,这些可以使用业务处理管理工具实现,比如,BizTalk Server编排。

4.  业务组件。 无论一个业务过程是否有单个步骤或者一个被编排的工作流组成,或许,你的应用程序将需要实现业务规则和执行业务任务的实现。例如,在零售应用程序中,你会需要实现计算货物全部价格和增加合适的交货费用的功能。业务组件实现应用程序的业务逻辑。

5.  服务代理。当一个业务组件需要使用一个外部服务提供的功能时,你可能需要提供一些代码管理和指定服务进行通讯的语义。例如,在前面我们描述的零售应用程序,使用服务代理管理和信用卡服务的通讯,使用第二个服务代理管理和快递服务的会话。服务代理具有独立的特性,它可以使你的应用程序和调用的各种各样的服务相互隔离,也可能提供其它服务,诸如,在被服务暴露数据的格式化和你应用程序需要的格式化之间, 有一个基础的映射。

6.  服务接口。对于一个服务暴露的业务逻辑,你必须创建服务接口,支持不同使用者的通讯契约(基于消息的通讯、格式化、协议、安全、异常等等)。例如,信用卡认证服务必须暴露一个服务接口,描述被服务提供的功能,和需要被调用的通讯语义。服务接口有时也被作为“业务外观”称呼。

7.  数据访问逻辑组件。许多应用程序和服务会在业务处理期间的某个点上,需要访问数据存储。例如,零售应用程序需要从数据库中获取产品数据,显示产品明细给用户,当用户提交一个订单时,需要插入订单明细到数据库中。在数据访问组件的隔离层中,把必须的访问数据抽象成逻辑是有意义的。如此,我们可以集中于数据访问功能,使它更容易配置和维护。

8.  业务实体组件:许多应用程序和服务需要在组件之间传递数据。例如,在零售应用程序中,产品列表必须通过数据访问组件传递给用户界面组件,以便产品列表显示给用户。数据被用于表现真实世界的业务实体,如,产品和订单。在应用程序内部使用的业务实体通常是一个数据结构,如,DataSetDataReader,或者XML流;但,也可以使用自定义的对象类来实现,这些对象类表现了你应用程序必须工作的真实世界的实体,如,一个产品或者一个订单。

9.  安全,运行管理和通讯组件:你的应用程序或许也需要使用组件执行异常管理,授权用户执行某些任务,和其它服务和应用程序通讯。这些组件会在第3章详细讨论。

 

应用程序和服务的一般设计建议

当在设计一个应用程序或者服务时,你要考虑以下建议:

l  识别出你应用程序需要的组件类型。有些应用程序不需要某些组件。例如,小型的应用程序不需要集成其它服务,不需要业务工作流或者服务代理。同理,仅有一个用户和很少的元素交互应用程序不需要用户处理组件。

l  对于指定类型的所有组件,尽可能地保持设计的一致性,使用一个设计模式或者少量的设计模式。这样有益于所有团队保持设计和实现的可预知性和可维护性。在有些情况下,可能很难维护一个逻辑设计是因为技术环境(比如,你同时开发ASP.NET和桌面用户界面);但是,你要争取在每个环境中保持一致性。在有些情况下,你可以使用一个基类为所有组件保持一个相似的模式,比如,数据访问逻辑组件。

l  在选择物理分布式边界之前,理解组件彼此是如何通讯的。通过选择粒度来保持低耦合和高内聚,而不是随意(chatty)的,和远程服务进行链接。

l  在应用程序或者服务中,保持数据交换格式使用的一致性。如果你必须混合数据表现格式,要争取尽可能少的数据格式化数量。例如,为了快速绘制数据,你在ASP.NET中使用DataReader从数据访问逻辑组件处获取数据,而不是在业务处理中使用耗时的DataSet。然而,要明白,在同一个应用程序中使用混合的DataSetXML字符串,序列化对象,DataReader和其它格式,将会为应用程序的开发、扩展和维护带来更多的困难。

l  从应用程序业务逻辑抽出一些策略,坚持编码执行这些策略(诸如,安全、运行管理和通讯约束)。努力依赖于属性(attributes),平台应用程序编程接口(API),或者工具化组件,提供“单线条的编码”(single line of code)与这些策略相关功能的通道。诸如,抛出异常,认证用户等等。

l  在一开始,确定你想执行的分层类型是什么。在一个严格的分层系统中,层A的组件不能调用层C的组件;他们总可以调用层B的组件。在许多不严格的分层系统中,一个层的组件调用其它层的组件,不是调用它下面的。在所有的情况下,努力避免向上调用和依赖,在这样的要求下,层C可以调用层B。你可以有选择性地实现不严格的分层,防止在一个层关闭底层改变时,产生瀑布式的影响;或者防止有些组件什么也不做,仅是为了调用在下面的层。