传统三层架构和MVC的再认知
前言
今天在我回顾传统三层架构的时候,我又重新看到了MVC。我就很懵,以前只知道三层架构,现在因为自己工作的原因又重新了解一下这些方面的知识。原来我之前了解的三层架构只是传统的三层架构,还有领域模型架构,还有MVC这个东西。接下来,我会一一带着大家了解这些架构。
第一个,我们都认识的传统的三层架构
传统三层架构是一种软件架构,是一种典型的、基于贫血模型的、面向过程的JavaWeb分层方式。该架构分为以下三个层次:
- 数据访问层(DAL - Data Access Layer)即对包括数据库在内的数据源进行操作的部分。
- 业务逻辑层(BLL - Business Logic Layer)即对业务数据进行逻辑处理的部分。
- 表现层(UI - User Interface)即与用户交互的部分。
分层的目的是为了解耦和明确责任。开发人员可以只关心自己所负责的那一层,因为他只需要知道上一层提供了哪些接口,从而利用这些接口进行编程。而上一层的开发人员在不改变接口的情况下,可以任意地替换具体的实现,从而实现松耦合。
相比更传统的架构,三层架构有着明显的优势,但也有不可忽视的缺点。初期的JavaWeb在JSP内同时进行数据库读写、业务逻辑处理和页面渲染,简单而暴力。而今的架构,在JSP之上增加了一个处理业务逻辑的中间层和一个封装了数据库操作的数据访问层,毫无疑问造成了代码量的大幅度上升和效率的下降。
这种分层体系结构具有以下四个优点:
(1)避免了表示层直接访问数据访问层,表示层只和业务逻辑层有联系,提高了数据安全性。
(2)有利于系统的分散开发,每一个层可以由不同的人员来开发,只要遵循接口标准,利用相同的对象模型实体类就可以了,这样就可以大大提高系统的开发速度。
(3)方便系统的移植,如果要把一个 C/S 的系统变成 B/S 系统,只要修改三层架构的表示层就可以了,业务逻辑层和数据访问层几乎不用修改就可以轻松的把系统移植到网络上。
(4)项目结构更清楚,分工更明确,有利于后期的维护和升级。
第二个,我新学习的领域模型架构
领域模型的概念源于2004年出版的经典著作《Domain-Driven Design –Tackling Complexity in the Heart of Software》(《领域驱动设计:软件核心复杂性应对之道》,简称DDD)。所谓领域,即软件所关注的主题区域:
每个软件程序的目的都是为了执行某项活动,或是满足用户的某种需求。用户会把软件程序应用于某个主题区域,这个区域就是软件的领域。一些领域涉及物质世界,例如机票预订程序的领域中包括飞机乘客在内。有些领域则是无形的,例如会计程序的金融领域。
该著作提出,设计软件分为两个步骤:
由领域专家、开发人员、设计人员就某一领域进行交流,从中发现领域概念,并根据需要,划定边界,将边界内的概念抽象为领域模型。
由领域模型驱动软件设计,用代码来实现该模型。
基于此,DDDSample官网提出了另一种三层架构
如图,该架构分为界面(Interfaces)、应用(Application)和领域(Domain)三层,以及一个基础设施(Infrastructure),是一种基于充血模型的、面向对象的分层方式。其各层职责如下:
1、界面层(Interface)
负责所有与外部系统的交互,包括WebService、RMI或REST等。包括外观(Facade)、装配(Assembler)和数据传输对象(DTO)三类组件:
- DTO组件
因为领域对象不适合暴露给用户,因此需要在返回给用户之前,重新封装为DTO,只暴露我们希望暴露的内容。同时,DTO还有减少请求的次数、简化传输对象、避免代码重复等作用。 - Assembler组件
Assembler是一个装配工人,负责DTO与领域对象的转换。 - Facade组件
Facade是外观模式的践行者,作用与传统三层架构的Controller类似,负责将一个或多个service方法组合起来,然后封装为一个接口提供为外部系统。换句话说,他负责将外部请求委派给一个或多个service进行处理。他本身不处理任何业务逻辑。
2、 应用层(Application)
应用层的主要组件就是Service,其粒度与传统三层架构的service一致。差别在于,传统三层架构的service层负责业务逻辑的处理,而领域模式三层架构的service只负责将业务委派给领域对象进行处理。
3、领域层(Domain)
- Entity/Value Object
实体是一个在业务领域有着唯一标识的对象。实体有属性和状态,有业务行为,其业务行为会影响他的属性和状态。而值对象呢,用于描述没有唯一标识的对象。举个栗子,当我们希望对每一辆共享自行车进行管理时,他应该被设计为实体,有唯一编号作为标识,有颜色、重量、价格、品牌等属性,有位置状态、使用状态,有租赁行为。当其被租赁时,其位置状态和使用状态可能发生改变。同样是共享自行车,如果我们的系统只为了统计各地区各品牌自行车的使用情况,即我们只关心他是什么,而不关心他是谁,那么他应该被设计为值对象。 - Repository
仓储类似于传统三层架构的DAO接口,但只是接口,不包括实现。 - Domain Event
简单的说,实体触发事件,实体绑定事件。用户的租赁行为会触发租赁事件;而自行车绑定了租赁事件,当事件发生时,自行车的使用状态发生改变。
4、基础设施(Infrastructure)
作为基础设施,Infrastructure负责给三层架构提供支持。所有与具体平台、框架相关的实现都会在这一层实现,以免影响三层架构职责的纯粹性、以及污染领域模型。对象持久化的具体实现也放在基础设施里。
传统三层架构和领域模型架构的区别
从领域模型架构各层的职责可以看出,他和传统三层架构最大的差别在于,领域模型架构的业务逻辑包含在领域模型里,而传统三层架构的业务逻辑在Service层。为了实现这一点,领域模型还引入了在Javascript和ActionScript中常见的事件机制;而传统三层架构中,领域模型的属性和行为严格分离,变成了POJO和Service。
个人认为,两种架构的出发点是相同的,一样是先挖掘领域概念,然后建模,再根据模型进行设计。差别在于,当业务逻辑的复杂程度在单个开发人员或单个团队的把控能力范围之内时,采用面向过程的传统三层架构可以很快地完成建模工作,并开始业务逻辑的设计;而当业务逻辑复杂到一定程度时,则有必要花更多的时间用在建模上,去抽取模型的行为,去设计和关联模型事件,以期在后续迭代中,开发人员只需面对一个个可以清晰地理解的领域对象,而不是一坨动辄上千行的某业务行为的逻辑代码。
综上考虑,大部分web系统可以采用传统三层架构。
模型的形态
不同的架构、不同的层、不同的应用场景中有着不一样的建模需求,因此表述相同概念的模型可能会有不同的“形态”,例如:
- 充血模型 - 领域模型架构中包含了领域逻辑和领域属性的领域模型。
- 失血模型 - 传统三层架构中只有get/set方法,没有业务逻辑的POJO对象。
- 贫血模型 - 类似充血模型,但是不包括持久化相关逻辑。
- PO - Persistant Object,持久化对象,即DAO从JDBC取出来的对象。传统三层架构中,PO即POJO组件中的对象,存在于DAO和Service之间。
- PO - Persistant Object,持久化对象,即DAO从JDBC取出来的对象。传统三层架构中,PO即POJO组件中的对象,存在于DAO和Service之间。
- DTO - Data Transfer Object,数据传输对象。上面在领域模型架构的界面层提过。对传统三层架构来说,该对象存在于Service和Controller之间。PO到DTO的转换可以在service实现,也可以在controller实现。本教程在Service进行转换。
- VO - View Object,视图对象。Controller在返回DTO给视图时,可能还需要包括状态信息—例如操作成功/失败的状态吗、提示文本等—这时就需要在DTO外面再包一层,即View Object。该对象存在于Controller和Web之间,由Controller进行装配。
第三个,MVC模式
MVC:
- M——Model(模型,即JavaBean)用来储存数据的组件(与领域模型概念不同,两者会相互交叉)
- V——View(视图,即页面)从Model中获取数据进行内容展示的组件。同样的Model在不同的View下可展示不同的效果。获取Model的状态,而不对其进行操作。
- C——Controller(控制层,即与前端交互的类)接受并处理用户指令,选择一个View进行操作。
JavaBeans :
①是Java中一种特殊的类(换言之:JavaBean就是一个Java类).
一个Java类 ,满足以下要求,则可称为一个JavaBean
a. public修饰的类,提供public 无参构造方法
b. 所有属性 都是private
c. 提供getter和setter方法
②从使用层面来看,JavaBean分为2大类:
a. 封装业务逻辑的JavaBean (eg:LoginDao.java 封装了登录逻辑)
b. 封装数据的JavaBean (实体类:eg:Student.java Vedio.java 。往往对应于数据库中的一张表,即数据库中有个Student表,项目中就有个Student.java类)
③JavaBean 是一个可以重复使用的组件,通过编写一个组件来实现某种通用功能,“一次编写、任何地方执行、任何地方重用”。
MVC模式是一种设计软件的模式,不是一种架构。
在传统三层架构中,MVC的理念被应用在表现层:View提交请求数据给Controller,Controller返回数据用于渲染View,两者之间以Model(VO - ViewModel)的形式进行通信。如下图:
Controller要返回数据给View,怎么给呢?这就要说到service、dao和controller了:
- controller:控制层,接收前端传过来的数据
- service:业务层,处理制层传过来的数据
- dao:数据访问层,即把业务层传过来的数据存放在数据库
Controller先调用service给它提供的接口,然后service又要调用DAO层给它提供的接口。
Service层是建立在DAO层之上的,建立了DAO层后才可以建立Service层,而Service层又是在Controller层之下的,因而Service层应该既调用DAO层的接口,又要提供接口给Controller层的类来进行调用,它刚好处于一个中间层的位置。
每个模型都有一个Service接口,每个接口分别封装各自的业务处理方法。
三层架构和MVC的区别
同样是架构级别的,相同的地方在于他们都有一个表现层,但是他们不同的地方在于其他的两个层。
在三层架构中没有定义Controller的概念。这是最不同的地方。而MVC也没有把业务的逻辑访问看成两个层,这是采用三层架构或MVC搭建程序最主要的区别。当然了。在三层中也提到了Model,但是三层架构中Model的概念与MVC中Model的概念是不一样的,“三层”中典型的Model层是由业务逻辑与访问数据组成的。而MVC里,则是以实体类构成的。
其次,MVC是表现模式(Presentation Pattern), 三层架构是典型的架构模式(Architecture Pattern)。 三层架构的分层模式是典型的上下关系,上层依赖于下层。但MVC作为表现模式是不存在上下关系的,而是相互协作关系。即使将MVC当作架构模式,也不是分层模式。MVC和三层架构基本没有可比性,是应用于不同领域的技术。
第五、总结笔记(突出重点)
- M 即Model(模型层),主要负责处理业务逻辑以及数据库的交互
V 即View(视图层),主要负责显示数据和提交数据
C 即Controller(控制层),主要是永作辅助捕获请求并控制请求转发 - 三层
UI界面层
BLL业务逻辑层
DAL数据访问层
三层是基于业务逻辑来分的,而mvc是基于页面来分的
MVC模式是一种复合设计模式,一种解决方案
三层是种软件架构,通过接口实现编程
三层模式是体系结构模式,MVC是设计模式
三层模式又可归于部署模式,MVC可归于表示模式
课后小知识
MVC是一种框架模式。 框架、设计模式这两个概念总容易被混淆,其实它们之间还是有区别的。框架通常是代码重用,而设计模式是设计重用,架构则介于两者之间,部分代码重用,部分设计重用,有时分析也可重用。在软件生产中有三种级别的重用:内部重用,即在同一应用中能公共使用的抽象块;代码重用,即将通用模块组合成库或工具集,以便在多个应用和领域都能使用;应用框架的重用,即为专用领域提供通用的或现成的基础结构,以获得最高级别的重用性。 框架与设计模式虽然相似,但却有着根本的不同。设计模式是对在某种环境中反复出现的问题以及解决该问题的方案的描述,它比框架更具象;框架可以用代码表示,也能直接执行或复用,而对模式而言只有实例才能用代码表示;设计模式是比框架更小的元素,一个框架中往往含有一个或多个设计模式,框架总是针对某一特定应用领域,但同一模式却可适用于各种应用。可以说,框架是软件,而设计模式是软件的知识。 框架模式有哪些? MVC、MTV、MVP、CBD、ORM等等; 框架有哪些? C++语言的QT、MFC、gtk,Java语言的SSH 、SSI,php语言的 smarty(MVC模式),python语言的django(MTV模式)等等 设计模式有哪些? 工厂模式、适配器模式、策略模式等等 简而言之:框架是大智慧,用来对软件设计进行分工;设计模式是小技巧,对具体问题提出解决方案,以提高代码复用率,降低耦合度。