如果读者有大型企业级应用开发经验的话,应该对于分层架构并不陌生,Ability也采用分层架构。本节我们讨论以下话题:
· 为什么我们需要将应用程序进行分层?
· 如果不分层,系统将会出现哪些问题?
· 常见的分层方式有哪些?
· Ability是如何进行分层的?
随着面向对象程序设计和设计模式的出现,人们发现,现实生活中的建筑学有很多理论都可以用来指导软件工程(即程序的开发)。比如,在开发时,我们会先对要盖的楼房进行评估和核算(软件项目管理);根据需求设计楼房的图纸(软件设计),而后根据设计把楼房的地基、骨架搭建出来(搭建框架);再根据不同工种将人员进行分工,有些去砌墙,有些去贴砖(前端编码,后台编码);最后进行验收测试,交付给用户使用。
软件应用开发与建筑学的分层目的是一致的,都是旨在根据不同的业务、不同的技术、不同的组织,结合灵活性、可维护性、可扩展性等多种因素,将应用系统划分成不同的部分,并使这些部分彼此之间相互分工、相互协作,从而体现出最大化价值。对于一个良好分层的应用来说,一般具备如下特点:
分层就是将相关的业务功能的类或组件放置在一起,而将不相关的业务功能的类或组件隔离开。比如我们会将与用户直接交互的部分分为“表示层”(Presentation Layer),将实现逻辑计算或者业务处理的部分分为“业务层”(Business Layer),将与数据库打交道的部分分为“数据访问层”(Data Access Layer)。
设计良好的架构分层是上层依赖于下层,而下层支撑起上层,但却不能直接访问上层,层与层之间通过协作来共同完成特定的功能。
层能够被单独构造,也能够被单独替换掉,最终不会影响整体功能。比如,我们将整个数据持久层的技术从Hibernate转成了EclipseLink,但不能对上层业务逻辑功能造成影响。
为了更好地理解分层的好处,我们先来看一下不分层的应用架构是如何运作的。
下面举一个Web应用程序的例子。在Web应用程序开发的早期,所有的逻辑代码并没有明显的层次区分,因此代码之间的调用是相互交错的,整体代码看上去错综复杂。譬如,在早期使用诸如ASP、JSP以及PHP等动态网页技术时,常会将所有的页面逻辑、业务逻辑以及数据库访问逻辑放在一起,很多时候就在JSP页面里面写SQL语句,编码风格完全是过程化的。
以下代码就是一个JSP访问SQL Server数据库的例子。
先不论这段代码是否正确,从实现功能上来讲,这段代码既处理了数据库的访问操作,还做了页面的表示,其中又夹杂着业务逻辑判断。还好这段代码不长,读下来还能够理解,但如果是更加复杂的功能,这种代码肯定是非常不清晰的,维护起来也相当麻烦。
早期的这种不分层的架构主要存在如下弊端:
· 代码不够清晰,难以阅读。
· 代码职责不明,难以扩展。
· 代码错综复杂,难以维护。
· 代码没做分工,难以组织。
目前,比较常用的、典型的应用软件倾向于使用三层架构(Three-Tier Architecture),即:
· 表示层(Presentation Layer):提供与用户交互的界面。GUI(Graphical User Interface,图形用户界面)和Web页面是表示层的两个典型的例子。
· 业务层(Business Layer):也称为业务逻辑层,用于实现各种业务逻辑,比如处理数据验证,根据特定的业务规则和任务来响应特定的行为。
· 数据访问层(Data Access Layer):也称为数据持久层,负责存放和管理应用的持久性业务数据。
图5-2展示了三层架构的架构图。
图5-2 三层架构
如果你仔细看这些层,应该会看到每一层都需要不同的技能:
· 表示层需要诸如HTML、CSS、JavaScript等前端技能,以及具备UI设计能力。
· 业务层需要编程语言的技能,以便计算机可以处理业务规则。
· 数据访问层需要具有数据定义语言(Data Definition Language,DDL)、数据操作语言(Data Manipulation Language,DML)以及数据库设计形式的SQL技能。
虽然一个人有可能拥有上述所有技能,但这样的人是相当罕见的。在具有大型软件应用程序的大型组织中,一般将应用程序分割为单独的层,使得每个层都可以由具有相关专业技能的不同团队来开发和维护。
一个良好分层的架构系统应遵循如下的分层原则:
· 每个层的代码必须包含可以单独维护的单独文件。
· 每个层只能包含属于该层的代码。因此,业务逻辑只能驻留在业务层,表示逻辑只能在表示层,而数据访问逻辑只驻留在数据访问层中。
· 表示层只能接收来自外部代理的请求,并向外部代理返回响应。这通常是一个人,但也可能是另一个软件。
· 表示层只能向业务层发送请求,并从业务层接收响应。它不能直接访问数据库或数据访问层。
· 业务层只能接收来自表示层的请求,并返回对表示层的响应。
· 业务层只能向数据访问层发送请求,并从其接收响应。它不能直接访问数据库。
· 数据访问层只能从业务层接收请求并返回响应。它不能发出请求到除了它支持的数据库管理系统(Database Management System,DBMS)以外的地方。
· 每层应完全不知道其他层的内部工作原理。例如,业务层可以对数据库一无所知,并且可以不知道或不必关心数据访问对象的内部工作原理。业务层可以不知道或不关心表示层如何处理它的数据。表示层可以获取数据并构造HTML文档、PDF文档、CSV文档或以其他方式处理它,但是这应该与业务层完全无关。
· 每层应当可以用具有类似特征的替代组件来交换这个层,使得整体可以继续工作。
简而言之,应用在一开始设计的时候,就要考虑系统的架构设计,以及如何将系统有效地分层。由于系统架构设计属于比较高级别的话题,本书不会琢磨太多,对这方面感兴趣的读者朋友,可以参阅笔者所著的《分布式系统常用技术及案例分析》一书,该书的第2章详细介绍了软件系统的常见架构体系。
从三层架构中,我们很容易识别出,Ability同样遵循图5-2所示的三层架构。
· Page Ability:代表表示层。
· Service Ability:代表业务层。
· Data Ability:代表数据访问层。
因此,开发人员在设计Ability时,应先考虑这个Ability需要完成什么样的功能,代表了哪个层次的业务。