N-Layer Architecure
分层架构
最通常的架构模式就是分层架构模式,即所谓的N层架构。这种模式对大部分JAVAEE应用程序来说是标准模式,因此被大部分架构师、软件设计师、开发者广泛知晓。由于分层架构模式和公司里传统的IT沟通以及组织结构非常类似,使得它成为大多数商务应用开发最自然的选择。
模式描述
在分层架构模式中,它将应用分成多个水平层,每个水平层在应用中担任一个专门的角色(比如表现层或者业务逻辑)。尽管分层架构模型并没有指定必须的层次个数以及类型,但大部分这种模型都由4个标准层次构成:表现层、业务层、持久层、数据库(图1)。在一些情况下,业务层和持久层可以合为一个单一的业务层中,特别是当持久层的逻辑(比如SQL或者HSQL)内嵌于业务层中。因此小应用程序通常只有三个层‑次,至于更大或者更多的复杂商业应用可能会包含5个或者更多的层次。在此架构中每层都有一个特定的角色和责任。比如,表现层负责处理所有用户交互和浏览器沟通的逻辑,业务层可能会负责执行和要求相关的特定业务。在分层架构中,每一层只需要围绕满足特定业务请求的工作形成抽象。比如表现层不需要了解或关心如何获取客户数据;它只需要按特定格式展示信息;同理,业务层也无需关心如何展示客户数据,甚至业务层都无需知道客户数据从哪里来;业务层只需要从持久层获取数据,运用这些数据执行业务逻辑,再把信息上传给表现层。
这种模型一个强大的特征是隔离开组件按照不同层次。每个层次中的组件只需要处理属于那个层次的功能逻辑即可。比如在展示层的组件只需要处理展示的逻辑,而业务层中的组件只需要处理业务逻辑。这样的组件分类方式便于建立高效的角色和责任制的模型,同时也会方便开发、测试、管理、维护应用,因为设计完善的组件接口以及限制的组件功能范围。
关键概念
注意在图1-2中,架构中的每个层次被标记为封闭状态。在该架构模式中,这是一个非常重要的概念。一个封闭的层次意味着当需要把消息从一层传递给另一层时,它必须先通过位于第一层正下方的那层,才能达到再下面的一层。例如,一个来自于表现层的要求,必须先通过业务层、持久层才最终到达数据库。
那么为什么不让表现层直接到达数据库呢?这样速度会更快。这里就牵涉到了一个关键概念叫层次分离。
层次分离意味着不同层次间互不影响,你在一个层次上的改动不会影响其他层次。如果你让表现层能直接访问持久层,会导致任何在持久层SQL上面的改动既会影响业务层也会影响表现层,这造成了应用中不同组件之间的强耦合影响,这样的应用架构也会变得难以修改。
层次分离也意味着不同层次间相对独立,因此不需要知道另一个层次的内部实现。理解这一点,考虑一个把表现层架构从JSP转换成JSF的大型重构项目,假设表现层和业务层间的协议不变,那么业务层不受重构的影响,不会受表现层架构改变的影响。
闭合的层次达成层次分离,会有助于不同层间互不影响,但是也有需要层次开放的时候。例如,假设在一个架构中,有一些需要被业务层次的通用服务组件,因此你想要加一个共享服务层。在种情况,创建一个服务层通常是一个好办法。因为架构上,它限制了访问这些共享服务层的必须是业务层而不是表现层。如果没有一个单独的服务层,在架构上就不会限制表现层对其的访问,这样也会造成管理访问权限变得困难。
在这个例子中,新服务层位于业务层下,意味着表现层不能直接访问该层。然后新的问题是,业务层需要穿越新服务层才能到达持久层,这不符合逻辑。实际上,这个问题可以通过设置开放层次解决。
在图1-3所示,服务层被标志成开放状态,意味着业务层允许跨越这层而直接访问持久层。这在逻辑上是相符的。
借助闭环或者开环层次的概念帮助我们定义架构中层次间的关系以及方向流,同时提供给设计者和开发师必要的信息去理解不同层次的访问限制。没有记录或者没能和层间合适地沟通通常会导致过紧的耦合以及脆弱的难以测试、维护、部署的架构。
模式实例
为更好描述分层架构怎样工作,考虑一个业务从业人员获取特定目标用户信息的需求,如图1-4所示。黑色箭头标志一路下到数据库的获取用户数据的请求流向,而红色箭头显示从下往上直到显示数据的屏幕这一数据反馈流向。在这个例子中,客户信息包含客户数据及订单数据(用户下的订单)。“用户屏幕”负责接收查询请求和显示用户信息,它并不知道数据在哪里、如何获取它、有多少数据库表格需要查询才能满足查询请求。一旦“用户屏幕”接收到查询客户信息的请求,它接着传递请求到“用户代理”模块。这个模块知道业务层中哪个模块可以处理该请求,同时知道如何调用该模块、传递哪些参数给该模块。业务层中的“用户类”负责收集所有业务请求需要的信息。该模块调用持续层的“用户数据访问接口”(Dao data access object)模块获取用户数据;调用“订单数据访问接口”模块获取订单信息。这些模块接着执行SQL语句去获得相关数据,再传递回业务层的“用户类”模块。一旦“用户类”获得数据,它会收集订单和用户信息两块数据同时传递回“用户代理”模块,“用户代理”模块继而传递数据回“用户屏幕”呈现给使用者。
从技术层面看,实际上有很多实现上述模块的方式。例如,在JAVA平台,用户屏幕可以是JSF和用户代理(作为bean部件管理者)的耦合。业务层的用户类可以是本地Spring或者远程EJB3的bean。数据访问部件可以做成简单的POJO,MyBatis XML Mapper 文件,或者原始JDBC调用或者Hibernate调用。从微软平台的视角,用户屏幕可以是使用.NET框架访问C#业务模块的ASP模块,同时用户和订单数据访问模块可以做成ADO(ActiveX Data Objects).
考虑
分层架构模式是一个稳定的通用模式,这使得它成为大部分应用程序的首选,特别是当你不确定使用哪个架构的时候。然而,当选择该模式时,从架构的角度,依然需要从很多方面进行考量。
首先需要注意的是污水池反模式architecture sinkhole anti-pattern,这种反模式描述了一种情况,当请求需要从多层间穿过,而穿过的层次(layer)只需要含有较少或者甚至不需要逻辑进行数据处理时。一个例子是,假设当表现层负责对用户获取业务数据需求这一操作做出反馈,表现层把需求传递给业务层,业务层继而直接传送给持久层,持久层继而调用简单的SQL查询命令获取用户数据。而后,数据一路一层层直接传回表现层,其他层次在此间,对数据没有额外的操作或者有复杂的逻辑计算。
每个层次结构都会至少有些污水池反模式的情况,关键在于,分析这种情况的百分比。通常“80-20规则”是一个示范是否处于污水池反模式的好例子。即,通常一个典型的组合是,20%的需求是简单的层间传递,80%的需求是传递层需要有相应的逻辑代码处理传输需求。然而,如果你发现比例是相反的,大部分需求是简单的层间传递,那么你需要开放一些层次,而这也使得层间分离不清楚,进而增加维护的难度系数。
另一个考量是,分层架构模式趋向于部署成一个集成的应用,即使你想把表现层和业务层分割到独立的部署单元。对于某些应用,这可能并不需要顾虑,但它会对部署、整体的鲁棒性、稳定性、性能、扩展性造成潜在的影响。
模式分析
下面表格包含分层结构模式的常用架构特征的评价和分析情况。这些评价是通过分析典型的模式范例,并衡量它趋向每个特征的能力和考量该模式所长而得出的。
整体的敏捷
评分:低
分析:整体的敏捷程度是能快速根据变化的环境反应的能力。虽然这种模式下,改变可以分散到不同的层次中,然而,由于该模式趋于一个集成的整体应用和其模块的紧密耦合性质,导致改变依然很艰难和耗时。
部署的方便
评分:低
分析:这取决于你如何实现这个架构,对于大型的应用,部署可能成为问题。一个小的改动需求,可能要求整个应用程序重新部署,计划,执行。从该模式特性出发,它不方便达成应用程序持续的交付流程,因此降低了该项的评分。
可测性
评分:高
分析:由于每个部件会属于特定的一个层次,其他的层次的作用可以被模仿或者消除,这使得该模式容易测试。比如,开发者可以模仿表现层的表现、反应,进而单独测试业务层,或者模仿业务层的动作,单独测试表现层。
性能
评分:低
分析:尽管一些层级架构可以表现出好的性能,然后从这个模式性质出发,它并不能有利于做出高性能程序,由于层间传递是缺乏效率。
可扩展性
评分:低
分析:由于该架构趋向高耦合度和集成程序的特质,应用程序通常难于扩展。你可以把各个层次分离到独立部署的应用中,或者复制整个应用到多个节点中,进而提高扩展性,但整体而言,覆盖的模块太广泛,这使得扩展的代价变得更昂贵。
开发容易性
评分:高
分析:该评分高的原因主要是该模式非常有名气以及实现过程不复杂。由于大部分公司开发应用正是按对应层次(表现、业务、数据)的功能来划分,这使得使用该模式成为一种自然的选择。公司的沟通和组织架构以及它开发软件的方式之间的联系,称为Conway’s law。具体你可以谷歌去搜索更多信息。