跳到主要内容

nstarter 框架层级结构设计

架构层级

为了满足复杂业务逻辑的架构描述需要,nstarter 使用三层架构 (3-tier application architecture) 模型来完整描述层级关系。对于更加复杂的重型企业级应用,可以进一步扩展整合为 n 层 (n-tier) 架构逻辑。通过分层设计的方式,实现系统纵向之间的高内聚,低耦合。

  • 展现层 / 用户服务层 (USL - User Services Layer)

    展现层位于业务应用的最上层,负责显示数据和接收用户输入的数据,为用户提供直接交互操作的入口。对于后台 Web 应用而言,展现层主要负责 API 接口数据的组织发送。

  • 业务逻辑层 (BLL - Business Logic Layer)

    业务逻辑层是系统架构中体现核心价值的部分,其关注点集中在业务规则的制定、业务流程的实现等与业务需求有关的系统设计。业务逻辑层在体系架构中的位置很关键,它处于数据访问层与展现层中间,起到了数据交换中承上启下的作用。

  • 数据访问层 (DAL - Data Access Layer)

    数据访问层是业务应用中持久层,负责数据库的访问,可以通过访问数据库,或者其他诸如文件/第三方 API 等进行数据 CRUD 持久化存储相关操作。

层级结构

层级实现

在架构分层基础上,层级实现由具体的业务层级与对应的辅助对象来完成。为了保持产品开发迭代的稳定性,层级具体实现过程中,应当注意保持开闭原则 (Open-Closed principle, OCP),对扩展开放,对修改关闭。

业务层级

  • 控制器 - Controller

    控制器是展现层的数据结构组织部分,其名称来源一 MVC (Model View Controller) 设计模式中的 Controller。控制器直接处理用户端输入的数据,同时也负责对返回结果的结构整理。控制器与路由 (Router) 一起共同构成了后台应用展现层的实现。

    • 在 API 请求场景下,控制器负责面向用户处理输入/返回的数据。
    • 在 html 页面访问场景下,控制器负责渲染返回 html 页面。

    从分层角度,控制器应当仅允许调用服务层的方法。

  • 服务 - Service

    服务层属于业务逻辑层,是实现业务逻辑的关键性核心,用于提取业务中抽象,或者可复用的业务逻辑。对降低业务代码的重复性,梳理业务逻辑具有重要的价值。

    服务层业务可以调用下层数据操作层的方法,也可以在服务层之间互相调用可复用的逻辑,但是不应该调用上层的控制器方法。

    对于应用内部的微服务治理而言,微服务组件互相之间的 RPC 调用,都可以理解成一种可复用的业务逻辑封装。所以,在 nstarter 框架中,应当由服务层来提供 RPC 业务。

    对于存在事务性 (transaction) 的操作,一般建议统一在服务层中提供相关逻辑的原子性封装。

    因为服务层方法之间可以互相调用的特性,对于服务层的实现,应当采用控制反转 (IoC) 的方式实现。

  • 仓库 - Repository

    仓库层属于数据访问层,其命名来源于仓库设计模式 (Repository Pattern)。仓库层用于切割应用业务对于数据源的依赖性,对数据访问对象的操作提供一层包装。对于复杂业务而言,如果只提供了 Model 层,往往会将相关数据操作逻辑实现到业务层,导致层级间依赖的问题。

辅助对象

  • 路由 - Router

    路由是展现层的入口,只负责梳理不同的请求,挂载业务中间件,将业务分发到不同的控制器方法上。

  • 数据模型 - Model (DAO)

    数据模型是数据访问层的最基础数据操作对象,是为某种类型的数据库或其他持久性机制提供一个抽象接口的对象。

  • 实体 - Entity (DTO)

    实体对象是一种独立于数据处理层级外的对象申明,用于实现业务数据结构的标准化定义,负责提供在各层级之间传递标准化的数据结构,提供面向用户的标准结构数据输出。同时,实体对象还可以提供面向用户输入参数的结构化校验,以及安全性初始化,保证内部逻辑对于数据对象使用的类型安全。

    ℹ Tips 在 v8 引擎中,对象存在两种模式,一种是用哈希表实现的 Dictionary mode,另一种是类似 C 语言中结构化的 Fast mode。对于比较复杂的对象数据结构,使用 class 声明可以直接创建快速对象,其使用效率在很多场景下会优于字典模式下的对象表现。

层级关系

层是一种弱耦合结构,层与层之间的依赖是向下的,底层对于上层而言是无感知的,改变上层的设计实现不应该对其调用的底层直接产生影响。就好比当业务逻辑进行改变时,底层的数据库接口并不会根据上层变更做调整。

另外,在分层设计时,应当遵循了面向接口设计的思想,从而可以使得层级间像下的依赖也成为一种弱依赖关系。因而在不改变接口定义的前提下,理想的分层结构应当是一种可以根据实际业务调整需要抽取/替换的抽屉结构。典型的场景有,更换底层数据库以后,仅需要更换数据访问层,而无需调整上层的业务层,即可完成业务在新平台上的实现。或者当业务层的计算性能不足时,可以直接对业务层中的相关模块实现方案进行替换。

理想状态下,各层级之间的通信,应当使用统一接口标准的数据转换对象 (DTO) 来进行数据传递。如果在各层级定义自己的参数结构标准,容易导致管理上的混乱,以及可维护性的下降,同时对消耗在数据结构转换上的性能优化也不利。用户数据在进入到路由层后,被直接加工成标准化对象,随后用于在后续各层级之间传递,初始化过程即可完成数据模型的结构安全性校验与规范化,保证后续各层级所调用的数据结构稳定性。