MVC开发问题面试与学习

为什么还要使用MVC三层开发?

大部分业务系统的开发都可以分为三层:Controller层,Service层,Repository层。对于这种分层方式,大部分人都比较认同,且已经成为了一种开发习惯。但自从学习了DDD之后,我对这种分层方式产生了一定的质疑,为此我探究了一下,可以作为一个面试题来提问或解答。具体原因总结如下:

1.分层能起到代码复用的作用

         同一个Repository可以会被多个Service调用,同一个service也会被多个controller调用。比如,UserService 中的 getUserById() 接口封装了通过 ID 获取用户信息的逻辑,这部分逻辑可能会被 UserController 和 AdminController 等多个 Controller 使用。如果没有 Service 层,每个 Controller 都要重复实现这部分逻辑,显然会违反 DRY 原则(Don't Repeat Yourself)。

2.分层能起到隔离变化的作用

      分层提现了一种抽象和封装的设计思想。比如,Repository层封装了对数据库访问的操作,提供了抽象的数据访问接口。基于接口而非实现编程的设计思想,Service层使用Repository层提供的接口,并不关心其底层依赖的是哪种具体的数据库。当我们需要替换数据库的时候,比如从MySQL到Oracle,只需要改动Repository层的代码,service层的代码完全不需要修改。除此之外,Controller,Service,Repository三层代码的稳定程度不同,引起变化的原因不同,所以分成三层来组织代码,能有效的隔离变化。比如,Repository 层基于数据库表,而数据库表改动的可能性很小,所以 Repository 层的代码最稳定,而 Controller 层提供适配给外部使用的接口,代码经常会变动。分层之后,Controller 层中代码的频繁改动并不会影响到稳定的 Repository 层。

3.分层能起到隔离关注点的作用

        Repository层只关注数据的读写,Service层只关注业务逻辑,不关注数据的来源。Controller层只关注与外界打交道,数据封装,校验,格式转换,并不关心业务逻辑,三层之间的关注点不同,分层之后,职责分明,更加符合单一职责原则,代码的内聚性更好。

4.分层能提高代码的可测试性

         单元测试不依赖不可控的外部组件,比如数据库。分层之后,Repository层的代码通过依赖注入的方式供Service层使用,当要测试包含核心业务逻辑的Service层代码的时候,我们可以用mock的数据源替代真实的数据库,注入到Service层代码中。

5.分层能应对系统的复杂性

        所有的代码都放在同一个类中,那这个类的代码就会因为需求的迭代而无限膨胀。我们知道,当一个类或一个函数的代码过多之后,可读性,可维护性就会变差。我们需要想办法拆分,拆分有垂直和水平两个方向。水平方向基于业务来做拆分,就是模块化。垂直方向基于流程来拆分,就是这里说的分层。

BO、VO、Entity存在的意义是什么?

针对Controller、Service、Repository三层,每层都会定义相应的数据对象,分别是VO(View Object),BO(Bussiness Object),Entity。例如UserVO,UserBO,UserEntity。在实际的开发中,VO,BO,Entity可能存在大量的重复字段,甚至三者包含的字段完全一样。在开发的过程中,我们经常需要重复定义三个几乎一样的类,显然是一种重复劳动。所以产生了以下几个问题

1.相对于每层定义各自的数据对象来说,是不是定义一个公共的数据对象更好一些呢?

实际上,我更加推崇每层都定义各自的数据对象这种设计思路,主要有以下3个方面的原因。

  • VO,BO,Entity并非完全一样,比如,我们可以在UserEntity,UserBo中定义Password字段,但显然不能再UserVO中定义Password字段,否则,就会将用户密码暴露出去。
  • VO,BO,Entity三个类虽然代码重复,但功能语义不重复,从职责上讲是不一样的。所以不违背DRY原则。即使合并到同一个类中,后期也需要进行拆分。
  • 为了减少每层之间的耦合,把职责边界划分明确,每层都会维护自己的数据对象,层与层之间通过接口交互。数据从下一层传递到上一层的时候,将下一层的数据对象转换成上一层的对象,再继续处理。虽然这样的设计稍微有些繁琐,每层都需要定义各自的数据对象,但分层清晰。对于非常大的项目来说,结构清晰是第一位的。

既然VO,BO,Entity不能合并,那如何解决代码重复问题呢?不同分层间的数据对象该如何互相转化呢?

没错,就是继承。可以将公共的字段定义在父类中,让VO,BO,Entity都继承这个父类,各自只定义特有的字段,因为这里的继承层次很浅,也不复杂,所以使用继承并不影响代码的可读性和可维护性。

关于对象转化,最简单的方式就是手动复制。自己写代码再两个对象之间,一个字段一个字段的赋值。但这样的做法很low,Java中提供了多种数据对象转化工具,比如BeanUtils,Dozer等。可以大大简化繁琐的对象转化工作。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值