在初学Spring时曾被Service绕晕,为何MVC模式下会多出一个Service层?设计Service时候为何需要先写一个接口,然后再去实现?Service之间是否可以相互调用?而这篇文章就是当初疑问的解决,也是对MVC模式深入理解。

Service从何而来

Spring MVC,是一个MVC框架,提到MVC,大家都不陌生,简单说一下,M为模型层,处理数据逻辑,V为视图层,负责展示,而C为控制层,负责M与V的交互。
在我大学的课堂上,也有学习到MVC模式,最简单的javabean+jsp+serlvet构成MVC模式,而老师千叮万嘱我们,Servlet中的逻辑一定要少,逻辑部分应该放在javabean,即模型层处理,但是模型层还肩负着存储数据的任务(其实这个就是Model所负责的数据逻辑,要实现数据逻辑,要有数据,要有处理),而Service就是将处理,也可以说业务,抽离出来,可以说是服务层,也可以说是业务层。MVC的划分概念,更加细致。

为什么设计Service时候需要先写接口

业务层接口

public interface IUserService {boolean login(User user);
}

业务层实现类

@Service("userService")
public class UserServiceImpl implements IUserService {public boolean login(User user) {//登录判断逻辑}
}

在初学时,我写Service时大概就是这种感觉,但并没有想过为什么要这样做。要想理解为什么要这样写Service,首先要理解,接口的作用是什么。

接口的作用

接口主要用于描述类具有什么功能,而并不给出每个功能的具体实现。一个类可以实现一个或多个接口,并在需要接口的地方,随时使用实现了相应接口的对象。——《Java核心技术卷一》

这句话所描述的就是接口所带来的扩展性。而用我的话去概括,就是「统一的接入」与「统一的暴露」,举一个例子来解释,数据源的接口DataSource
统一的接入是对于数据源的开发者来说,要实现数据源,就需要去实现DataSource接口,然后实现其方法。对于DBCP、c3p0、Druid数据源来说,不同的开发者,实现同一套东西,这就是统一的接入。
统一的暴露是对于数据源的使用者来说。对于数据源的使用者,使用时所要关注的是如何获取数据库连接的动作,即getConnection方法,至于这个动作的具体实现,不需要知道也不关心。
统一的接入与统一暴露,将实现与使用分离开来,也就是接口所带来的好处。
开头所写的IUserService的例子,所做的就是将登陆的实现与使用分离,举一个具体的例子

@Service("databaseUserService")
public class DatabaseUserServiceImpl implements IUserService {public boolean login(User user) {//从数据库查询用户信息,判断是否账号/密码是否一致}
}
@Service("oauthUserService")
public class OauthUserServiceImpl implements IUserService {public boolean login(User user) {//使用Oauth登陆,如微信登陆}
}

对于登陆的实现,就可以分为从数据库查询和使用第三方授权登陆两种方式分别实现,对于使用者来说,所关注的就是login这一动作,整个登陆操作变得十分灵活,根据不同的场景使用不同的方式登陆。
看起来这种实现Service的方式非常不错,以后写Service都这样写吧。
想一下之前所写的代码,通常都是一个Service接口对应一个实现,基本上是没有第二个实现的必要,也就是所获取到接口的好处非常少,但是却付出了实现接口的代价,即对动作的抽象,这是一个成本,例如你想为Service添加功能,你需要先将这个功能抽象出来,其中的参数,返回值都要定好,如果需求改动,改动这个功能的功夫是不少的。这样的话,为何不去除这个借口,直接实现Service类呢?

去除接口,让Service成为业务

将接口去除,其实是将Service层,从服务改变为业务,即专注于业务,Service中的都是业务逻辑。有何区别呢?简单点来说,不用考虑向外提供服务,只为自己系统的业务功能提供服务。
对于一个中小项目来说,脱掉Service层接口的枷锁,实现起业务来,十分流畅,不再用抽象,只关注于业务即可。
在学校时,一位师兄经常提醒我,知其然知其所以然,只有清楚为何写Service时需要先写接口,才能明白为何要去除接口。

Service的互相调用

Service间是否可以相互调用,这个很久当时是在困扰了我很久,现在可以明确的说,Service层不应该相互调用,特别是我上面提到的去除接口,让Service完全成为一个业务体的设计下,更加不应该相互调用Service。
你会问,一个Service的实现的业务,确实可以在另一个Service中用到,难道要重新写?要清楚,这个情况是出于Service间有通用的逻辑,而不是通用的业务,每个Service对应一个业务,业务之间应该有明确的分界,不然会出现业务间的耦合,这是设计的不合理。
既然是Service间的逻辑通用,我们大可创建一个ServiceHelper类,里面放的,就是Service间的通用逻辑,各自调用这个逻辑即可。当然如果系统庞大起来,这种情况会经常出现,这时再抽象一层,可以叫provider层,提供操作逻辑,例如发短信功能,provider里放的是如何发短信的操作逻辑,而Service层放的是什么时候发短信,发多少,发给谁的业务逻辑。

业务逻辑只由Service自己知道

上面所写的UserService例子

@Service("userService")
public class UserService {public boolean login(User user) {//登录判断逻辑}
}

这样写,我觉得还不是最好。这个Service最终会被一个Controller所调用,当Controller调用该方法时,还需要判断返回值是true还是false,再返回结果,其逻辑“泄露”了,因为Controller要了解业务是true是登陆成功,false是登陆失败。如下

@Controller @RequestMapping("/user") public class UserController extends BaseController {

@Autowired
private UserService userService;@RequestMapping(value = "/login", method = RequestMethod.POST)
public
@ResponseBody ResponseResult login(@RequestBody User form) {if(userService.login(form)) {return ResponseResult.getOk("登陆成功");} else {return ResponseResult.getError("登陆失败");}
}

}

Controller不应该知道怎么才算登陆成功,登陆失败,它应该只需要知道调用那个业务。
我们可以这样写

@Service("userService")
public class UserService {/** * @return ResponseResult响应结果.为{"status":"状态码","msg":"响应信息","data":"响应数据"} */public ResponseResult login(User entity) {//用MD5加密密码entity.setPassword(MD5Utils.getMD5(entity.getPassword()));//用账号和加密后的密码为查询条件,查询数据库中是否有对应的数据Optional<User> optional = userRepository.selectOne(entity);return optional.map(ResponseResult::getOk).orElseGet(() -> ResponseResult.getError("账号/密码错误"));}
}
@Controller
@RequestMapping("/user")
public class UserController extends BaseController {
@Autowired
UserService userService;@RequestMapping(value = "/login", method = RequestMethod.POST)
public
@ResponseBodyResponseResult login(@RequestBody User form){return userService.login(form);}
}

这样写,不就向Controller屏蔽了登陆是否成功的判断逻辑。
平时我们一直说,Controller一定要尽量少的逻辑,其实反过来说,是指Service的逻辑应该高内聚,这样Controller如Service的耦合自然就是最低,Controller真真正正的坐到,不用理会Service的实现,只需要调用即可。
当然这个登陆的例子可能有点小题大做,但是如果这个业务是查找一批用户,如果查找不到需要返回错误码呢?难道要在Controller层去判断返回的集合是否为空,然后构造返回信息吗?这样其实是将Service的部分逻辑放在了Controller去完成。

转载https://my.oschina.net/bingzhong/blog/1559856

如何设计Service层相关推荐

  1. javaweb开发设计Service层

    Service从何而来 Spring MVC,是一个MVC框架,提到MVC,大家都不陌生,简单说一下,M为模型层,处理数据逻辑,V为视图层,负责展示,而C为控制层,负责M与V的交互. 在我大学的课堂上 ...

  2. SSM框架中各层的含义和联系(Pojos层、Dao层、Service层、Action层......)

    一.pojo层 即Plain Ordinary Java Object,也有人称其为model.domain.bean等,pojo层是对应的数据库表的实体类. 二.1.持久层:Dao层(Mapper) ...

  3. 【转】DAO层,Service层,Controller层、View层

    DAO层:DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,DAO层的设计首先是设计DAO的接口,然后在Spring的配置文件中定义此接口的实现类,然后就可在模块中调用此接口 ...

  4. java的dao层_Java中Dao层、Action层、Service层、Controller层-Fun言

    Action/Service/DAO简介 Action 管理业务(Service)调度和管理跳转 Service 具体的业务功能 Action只负责管理,而Service负责实施 DAO只完成增删改查 ...

  5. DAO层,Service层,Controller层、View层

    转载:http://blog.csdn.net/zdwzzu2006/article/details/6053006 DAO层:DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在 ...

  6. Springboot三层架构--DAO层、Service层、Colltroler层--这波我在外太空

    目录 1.DAO层 Dao层的设计 2.Service层 Service层的设计 设计Service层的优点 Dao与Service的关系 3.Colltroler层 Collertroler层的设计 ...

  7. MIna框架I/O Service层设计

    Mina从2.0版本以后,它的设计让人感觉到非常的优雅.它对网络应用通信框架的3个层进行了更好的抽象,以及在功能逻辑上的划分,同时又保证了 作为一个网络应用通信框架的统一.划分的3个层分别为: I/O ...

  8. service 层 拼接的html 代码如何直接返回_代码分层的设计之道

    分层思想,是应用系统最常见的一种架构模式,我们会将系统横向切割,根据业务职责划分.MVC 三层架构就是非常典型架构模式,划分的目的是规划软件系统的逻辑结构便于开发维护.MVC:英文即 Model-Vi ...

  9. Spring Boot开发基于三层架构设计:Dao层、Service层、Controller层

    三层架构设计:基于Spring Boot开发要使用三层架构: 数据访问层(Dao).业务逻辑层(Service).控制层(Control-ler) (1)数据访问层(Dao):Dao层是最底层的设计, ...

最新文章

  1. 机器学习——使用Apriori算法进行关联分析
  2. 可以直接用的“ html转字符串string”方法
  3. IDOC 创建,增强,管理,配置
  4. jquery 流程图_使用 JQuery.Flowchart
  5. 计算机专业好的211大学6,计算机专业好的985大学有哪些?附985211计算机大学名单排名...
  6. python3精要(4)-python数字与表达式1
  7. java 十六进制浮点_Java十六进制浮点文字
  8. 翻译 - EXT JS 5:Controlling an Application with Router
  9. 一步一步写算法(之循环和递归)(转)
  10. 万字长文带你解析23 个问题 TCP 疑难杂症!
  11. Linux wget命令入门
  12. 统计/var/log/下有多少文件
  13. 代码雨和N个本地磁盘的制作
  14. python调用QQ音乐API
  15. android实现高德地图集成
  16. 使用XMind打开.mmap文件不显示问题
  17. NetBeans 尚未部署该模块错误 解决方案
  18. css网页布局问题,CSS网页布局常见问题小结
  19. 如何做一个好的管理者
  20. CentOS8永久修改主机名

热门文章

  1. 如何用Git下载更新和上传项目此文只适合小白
  2. Mindjet 与 Trello 任务管理解决方案之一决高低
  3. mgr mysql_MySQL MGR集群搭建
  4. 能进复试的情况下,浙大MBA提面优秀良好其它三档考生录取率一观
  5. 【MYSQL】表的综合查询
  6. 淘宝运费险的赔偿问题
  7. 用Excel绘制皮尔逊三型曲线
  8. 推荐一些手机游戏开发会用到的网站
  9. Oracle 字符串拼接分号
  10. shell语法----expr命令