关于三层架构,可以参考:三层架构(我的理解及详细分析)
这篇13年古老的文章通过映射到现实生活将其讲得通熟易懂,本文也是学习本文中内容进行简单补充说明而来。
三层架构顾名思义就是将Web应用划分为三个层次,这三个层次分别为:显示层(User Interface layer)、业务逻辑层(Business Logic Layer)和数据访问层(Data access layer)。
之所以要进行分层处理,其核心目的之一固然是为了达到所谓 “高内聚,低耦合” 的思想。这样可以使开发人员间分工更加明确,将精力更加专注在应用系统核心业务逻辑的分析、设计和开发,加快项目的进度,提高了开发效率,有利于项目的更新和维护工作。
三层架构:
表示层(UI层)
:
表示层最外层,即离用户最近的一层。该层用于显示数据和接受用户输入的数据,为用户提供一种交互式操作的界面。
业务逻辑层(BLL层)
:
该层负责关键业务的处理和数据的传递,复杂的逻辑判断和涉及到数据库的数据验证都需要在此层做出处理。该层主要是针对具体的问题的操作,也可以理解成对数据访问层的操作,对数据业务逻辑进行处理。如果说数据层是积木,那逻辑层就是对这些积木的搭建。
数据访问层(DAL层)
:
主要负责对数据库的直接访问,通过不同的技术操作数据库为业务逻辑层提供数据,同时可以根据传入的值来操作数据库的增、删、改、查操作。该层可以将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。
那么,经过上面的了解,一个合理的流程就浮出水面了。根据上面三层的描述,我们便得到了如下的关系图:
从上图可以看出,大致流程为用户的请求反映给表示层(UI),表示层将用户的请求反映给业务逻辑层(BLL),然后业务逻辑层接着反映给数据访问层(DAL),数据访问层接收到请求后,对数据进行操作(增、删、改、查),操作后再按照原路径逐层返回,直到将用户所需要的数据展示到表示层(UI)从而反馈给用户。
但是这也随之带来一个问题,这三层之间是如何进行传递的?或者说这三层是如何联系起来的呢?
实体层(Entity)引入:
实体层不属于上面三层中的任何一层,但是三层之间想要联系起来,又离不开实体层。
简单来说,我们可以将实体层理解为数据库中的一张表。每张数据表对应一个实体,每个数据表中的字段对应实体中的一个属性。那我们就拿一张表来进行说明,如下提供了一张数据库菜单表menu:
我们使用Java面向对象的思想将这张表创建一个对应的 Menu.class 类然后进行封装处理,Menu类中属性和数据库menu表中的字段一一对应,Menu类的对象和数据库中menu表中的记录相对应。
那么我们便会得到一个完整的Menu.class 如下:
public class Menu {
private int sid;
private String sname;
private int count;
public Menu() {
}
public Menu(int sid, String sname, int count) {
this.sid = sid;
this.sname = sname;
this.count = count;
}
public Menu(String sname, int count) {
this.sname = sname;
this.count = count;
}
/**
* Getter and Setter
*/
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
当然,事实上不是这样。因为可能我们需要的实体在数据表对应的实体中并不存在,我们完全可以将所有数据表中的所有字段都放在一个实体里,所以上面仅是为了便于理解的假设情况。
每一层(表示层—>业务逻辑层—>数据访问层)之间的数据传递就是靠实体作为参数来传递的,这样就构造了三层之间的联系,完成了功能的实现。用实体做参数不用考虑参数匹配的问题,用到实体中哪个属性,直接通过 Getter 方法拿来用就可以,即方便也提高了效率。
这里为什么说可以暂时理解为每个数据表对应一个实体?
我们做系统的目的是为用户提供服务,用户不关心你的系统后台是怎么工作的,只关心软件是否好用,界面是否符合自己心意。用户在界面上轻松的增、删、改、查,那么数据库中也要有相应的增、删、改、查,而增删改查具体操的作对象就是数据库中的数据。所以,将每个数据表作为一个实体类,实体类封装的属性对应到表中的字段,这样实体在贯穿于三层之间时,就可以实现增删改查数据了。
综上所述:三层及实体层之间的依赖关系如下 ⬇️
上面的说法可能略显生涩,故下面引用文章顶部推荐文章的思想进行举例:
服务员-厨师-采购员案例:
三者各负其职,服务员不用了解厨师如何做菜,不用了解采购员如何采购食材;厨师不用知道服务员接待了哪位客人,不用知道采购员如何采购食材;同样,采购员不用知道服务员接待了哪位客人,不用知道厨师如何做菜。
顾客直接和服务员打交道,顾客(用户)和服务员(UI层)说:我要一个炒茄子,而服务员不负责炒茄子,她就把请求往上递交,传递给厨师(BLL层),厨师需要茄子,就把请求往上递交,传递给采购员(DAL层),采购员从仓库里取来茄子传回给厨师,厨师响应做茄子的方法,做好炒茄子后,又传回给服务员,服务员把茄子呈现给顾客,这样就完成了一个完整的操作。这个过程中我们只需要通过将实体作为参数传递,从实体中取出对应的属性 “茄子” 即可,当客户有更多的需求时我们使用同样的方式取出对应的属性即可。
解藕:
三层之间相互分离,各个层次分工明确,通过实体建立连接,因此任何一层发生变化都不会影响到另外一层,体现了“高内聚,低耦合” 的思想。
代码复用:
分层的根本在于代码的复用,以简化开发复杂性。分层的最理想化的结果是实现层与层之间互不依赖的内部实现,即所谓的即插即用,如我们使用mysql数据库,有一天换成 Oracle 只需要修改 数据访问层即可,直白点说就是只需要修改JDBC部分即可,而不会影响到其余两层。
利于团队开发:
三层架构由于各层相互独立,且分工明确,这使得团队开发成为可能,即一个小组只需负责一个板块即可。由于结构化设计在大型项目中必定会使程序变得错综复杂,其逻辑主要在业务逻辑层(BLL),就使得显示层(UI)也就是客户端不承担太多的职责,即使更新业务逻辑,也无需修改客户端,不用重新部署。
在此之前建议您先阅读MVC设计模式。
我们先来看看三层架构图:⬇️
再来看看MVC设计模式图:⬇️
不难看出,MVC设计模式其实就是由三层架构模式的表示层演变而来的。二者之间联系如下:⬇️
其实,无论是MVC还是三层架构,都是一种规范,都是奔着"高内聚,低耦合"的思想来设计的。三层中的UI和Servlet来分别对应MVC中的View和Controller,业务逻辑层是来组合数据访问层的原子性功能的。在三层中,业务逻辑层和数据访问层要遵循面型接口编程的。这种接口定义和具体实现逻辑的分开,非常有利于后续扩展和维护!
了解了上面的三层架构与MVC之间的关系,那么我们实际在项目创建过程中一般采用三层结合MVC的方式进行开发。下面给出一个简单项目目录以供参考:⬇️
参考资料:
- https://www.runoob.com/w3cnote/three-tier-architecture.html
- https://baike.baidu.com/item/%E4%B8%89%E5%B1%82%E6%9E%B6%E6%9E%84?fromModule=lemma_search-box
- https://iqqcode.blog.csdn.net/article/details/104963392?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-104963392-blog-90753696.pc_relevant_3mothn_strategy_recovery&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-104963392-blog-90753696.pc_relevant_3mothn_strategy_recovery&utm_relevant_index=6