系统架构:经典三层架构
Posted @一鸣惊人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了系统架构:经典三层架构相关的知识,希望对你有一定的参考价值。
引言
经典三层架构是分层架构中最原始最典型的分层模式,其他分层架构都是其变种或扩展,例如阿里的四层架构模式和DDD领域驱动模型。阿里的 四层架构模型在三层基础上增加了 Manager 层,从而形成变种四层模型;DDD架构则在顶层用户界面层与业务逻辑层之间引入应用层,从而形成变种DDD领域驱动模型;具体可参考《系统架构:分层架构》。
架构理念
三层架构基于“高内聚,低耦合”的思想,把各个功能模块划分为表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)。三层架构如图一所示。
表示层(UI) 位于三层构架的最上层。与用户直接接触,实现系统与用户直接的交换,以及消息事件的处理。UI层调用业务逻辑层BLL相关接口完成业务操作。
业务逻辑层(BLL),实现数据处理和数据传递,将界面表示层和数据访问层连接起来,起到承上启下的作用。
数据访问层(DAL),实现数据的增加、删除、修改、查询等操作,并将操作结果反馈到BLL层;
BLL处理的数据来自数据库和用户界面,其将用户界面收集过来的数据经过业务逻辑层的处理传送到数据库,而从数据库获取的数据,经过业务逻辑层处理后再呈现给用户界面。因此业务逻辑层是中间层,起到承上启下的作用。
经典三层架构的调用关系是:UI调用BLL,BLL调用DAL。而UI与DAL是不可直接相互调用,它们之间相互隔离。
基于 “高内聚,低耦合”理念的三层架构,使得开发人员分工更明确,可以让开发人员的精力更专注于应用系统核心业务逻辑的分析、设计和开发,加快项目的进度,提高了开发效率,有利于项目的升级和维护工作。
体系结构
三层架构的各层之间采用接口相互访问,并通过对象模型的实体类(Model)对象作为数据传递的载体,不同的对象模型的实体类一般对应于数据库的不同表,实体类的属性与数据库表的字段名一致。
表示层和业务逻辑层之间用对象模型的实体类(Model)对象来传递数据,业务逻辑层和数据访问层之间用对象模型的实体类(Model)对象来传递数据,数据访问层通过ORM组件来操作数据库。在DAL和数据库之间,通过ORM实现二维表关系数据和实体类(Model)对象的映射。三层架构的体系结构如图二所示。
因此三层构架中除了三层之外,还有实体类(Model)对象这最为重要的组成部分。实体类(Model)对象使用实体(Entity)表示,它不属于三层中的任何一层。也就是说实体类(Model)对象可以被三层中的任何一层调用。实体(Entity)与三层的关系如图三所示。
实体类(Model)对象Entity,具体有三个作用:
- 实体实现面向对象思想中的"封装”。
- 实体贯穿于三层之间,并在三层之间传递数据。
- 相邻层之间的单项数据传递依靠变量或实体作为参数来传递,这样就构造了三层之间的联系,从而完成功能实现。
优缺点
优点
- 可以让开发人员只关注整个架构的某一层;
- 分层清晰,开发分工也更明确,有利于后期的维护和升级;
- 单向调用,不允许跨层调用,可以很大程度上降低层与层之间的依赖耦合
缺点
- 三层之间数据传输都通过实体类(Model)对象实现,实体类的变化将导致三层都需要修改。从而增加维护的工作量,也使得产生Bug的风险加大。
- 三层之间数据传输都通过实体类(Model)对象实现不利于数据安全。例如一个数据表t_user,其字段包括userName, password, age等信息;password和age是客户的私人信息,这将导致这些数据在三层直接可以随意获取和展示,这是极不合适的。
总结
经典三层架构是分层架构中最原始最典型的分层模式,掌握经典三层模式是理解其他分层模型的基础。本文从三层架构的理念,架构体系,优缺点等三个角度对经典三层架构进行了深入分析。
六边形架构设计
分层架构是运用最为广泛的架构模式,把一个软件系统进行分层,是我们目前做工程项目的一个共识,我们最初学习的分层架构就是经典的三层架构了。它自顶向下分成三层:
- 用户界面层(User Interface Layer)
- 业务逻辑层(Business Logic Layer)
- 数据访问层(Data Access Layer)
在传统的单体应用中,因为业务不算复杂,这种分层并没有什么问题,把数据的渲染交给用户界面层,把核心业务逻辑放到业务逻辑层,然后将数据库的访问交给数据访问层。
但是随着业务越来越复杂,问题也随之而来:
- 需要依赖的基础设施也不仅仅只有数据库这样单一了
- 很多参数的校验,我们开始纠结是放到用户界面层还是业务层。
- 缓存是放到哪里去控制
......
代码开始变得复杂,很快只有上帝能看懂了,然后写代码往往就是牵一发而动全身。
我们都知道在设计模式中有一个很重要的原则就是依赖倒置,他包含了三层含义:
- 高层模块不应该依赖低层模块,两者都应该依赖其抽象
- 抽象不应该依赖细节
- 细节应该依赖抽象
所以设计模式中产生了一个模式——适配器模式:
将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
在中间件软件爆发的今天,同一种功能的中间件可能会有非常多的选择。比如:
- MQ: RabbitMQ, Kafka, ActiveMQ, RocketMQ......
- SQL: MySQL, PostgreSQL......
- NoSQL: Redis,MongoDB, ElasticSearch......
- Job: Elastic-Job, XXL-JOB.....
......
除此之外还有各种供应商的需要有备用通道:短信,邮件,推送,业务供应商......
如果我们在业务逻辑中去关注这些东西,毫无疑问,我们的业务逻辑就会很繁琐:
if ( config == ‘A‘ ) {
// statement 1
} else if ( config == ‘B‘ ) {
// statement 2
} else if ( config == ‘C‘ ) {
// statement 3
} else if ( config == ‘D‘ ) {
// statement 4
} else {
// default statement
}
特别是业务中去选择供应商的时候,我们通常是要有好几个备用通道的,但是我们的业务逻辑本身只是关心:这件事做了没,而不是到底用哪种方式去做。
所以六边形架构被提出了。六边形架构提倡用一种新的视角来看待整个系统,该架构中存在两个区域,分别是“外部区域”和“内部区域”。在外部区域中,不同的客户均可以提交输入;而内部的系统则用于获取持久化数据,并对程序输出进行存储(比如数据库),或者在中途将输出转发到另外的地方(比如消息)。
我们在设计系统的时候,往往过于关注数据库,Http接口等基础设施的设计,而忽略了我们需要关注的业务。在复杂系统中,最容易变化的也是业务形态,产品经常会要求改来改去,因为业务本身就在不断地演进,如果我们一开始就基于数据库作所有的设计,那么势必一旦遇上业务的修改,库表肯定也需要对应先进行变化。假如我们融入六边形架构,将数据库和暴露的Controller都视为是基础设施,先去关注业务的模型和代码,Class的修改比要数据库改起来要简单的多。另外一方面,也大大提高了程序的可测试性:在没有准备一堆基础设施(数据库,接口,异步通知等等)情况下,可以先测试逻辑的完整性。
另外,有时候随着业务增长有的基础设施是会需要进行替换的,采用六边形架构之后,这种更换的成本就会降低。另外如果出现需要使用Web Service的客户,我们也不必纠结于之前的HTTP接口,直接开出一套新的协议代码供客户使用,而不会纠结领域部分代码有逻辑上的缺失。
采用六边形架构之后,我们的领域模型也会更加独立,更精简,在适应新的需求时修改也会更容易。
以上是关于系统架构:经典三层架构的主要内容,如果未能解决你的问题,请参考以下文章