3.1.1 介绍
在我们进行程序设计以及程序开发时,尽可能让每一个接口、类、方法的职责更单一些(单一职责原则)。
单一职责原则:一个类或一个方法,就只做一件事情,只管一块功能。
这样就可以让类、接口、方法的复杂度更低,可读性更强,扩展性更好,也更利用后期的维护。
我们之前开发的程序呢,并不满足单一职责原则。下面我们来分析下之前的程序:
那其实我们上述案例的处理逻辑呢,从组成上看可以分为三个部分:
-
数据访问:负责业务数据的维护操作,包括增、删、改、查等操作。
-
逻辑处理:负责业务逻辑处理的代码。
-
请求处理、响应数据:负责,接收页面的请求,给页面响应数据。
按照上述的三个组成部分,在我们项目开发中呢,可以将代码分为三层:
-
Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
-
Service:业务逻辑层。处理具体的业务逻辑。
-
Dao:数据访问层(Data Access Object),也称为持久层。负责数据访问操作,包括数据的增、删、改、查。
基于三层架构的程序执行流程:
-
前端发起的请求,由Controller层接收(Controller响应数据给前端)
-
Controller层调用Service层来进行逻辑处理(Service层处理完后,把处理结果返回给Controller层)
-
Serivce层调用Dao层(逻辑处理过程中需要用到的一些数据要从Dao层获取)
-
Dao层操作文件中的数据(Dao拿到的数据会返回给Service层)
思考:按照三层架构的思想,如何要对业务逻辑(Service层)进行变更,会影响到Controller层和Dao层吗?
答案:不会影响。 (程序的扩展性、维护性变得更好了)
3.1.2 代码拆分
我们使用三层架构思想,来改造下之前的程序:
-
控制层包名:xxxx.controller
-
业务逻辑层包名:xxxx.service
-
数据访问层包名:xxxx.dao
我们写的Dao的代码会被service调用的 然数据访问Dao的实现方式可能有很多 比如我们访问的可能是文件的数据 可能是数据库的数据 也可能是别人给我们提供的接口获取到的数据,实现的方式有很多 而我们要是想灵活的切换各种实现 我们在SE阶段讲过 可以通过面向接口的方式进行编程
所以在编写Dao层具体实现之前 我们要先定义一个dao的接口 来增加程序的灵活性和拓展性
Dao层的实现类
package com.itheima.dao.impl; import com.itheima.dao.EmpDao; import com.itheima.pojo.Emp; import com.itheima.utils.XmlParserUtils; import java.util.List; /** * ClassName: EmpDaoA * Package: com.itheima.dao.impl * Description: * * @Author 小白 * @Create 2024/4/19 17:28 * @Version 1.0 */ public class EmpDaoA implements EmpDao { @Override public List<Emp> listEmp() { //1. 加载并解析emp.xml //getClassLoader():反射 String files = this.getClass().getClassLoader().getResource("emp.xml").getFile(); String file = files.replaceAll("20%", ""); System.out.println(file); List<Emp> empList = XmlParserUtils.parse(file, Emp.class); return empList; } }
写EmpService接口
写Service接口实现类
package com.itheima.service.impl; import com.itheima.pojo.Emp; import com.itheima.service.EmpService; import java.util.List; /** * ClassName: EmpServiceA * Package: com.itheima.service.impl * Description: * * @Author 小白 * @Create 2024/4/19 17:41 * @Version 1.0 */ public class EmpServiceA implements EmpService {private EmpDao empDao =new EmpDaoA(); @Override public List<Emp> listEmp() {//1.调用dao,获取数据 List<Emp> empList = empDao.listEmp();//2. 对数据进行转换处理 - gender, job empList.stream().forEach(emp -> { //处理 gender 1: 男, 2: 女 String gender = emp.getGender(); if("1".equals(gender)){ emp.setGender("男"); }else if("2".equals(gender)){ emp.setGender("女"); } //处理job - 1: 讲师, 2: 班主任 , 3: 就业指导 String job = emp.getJob(); if("1".equals(job)){ emp.setJob("讲师"); }else if("2".equals(job)){ emp.setJob("班主任"); }else if("3".equals(job)){ emp.setJob("就业指导"); } }); return empList; } }
Controller要用到Service的数据 所以我们可以在Controller层里面来创建Service实现类的对象,private EmpService empService = new EmpServiceA();用这个对象去调用service的接口 来获取service的数据
//1.调用service,获取数据 List<Emp> empList = empService.listEmp();
Service要用到Dao的数据的时候 我们可以在Service实现层里面来创建Dao实现类的对象,private EmpDao empDao =new EmpDaoA();用这个对象去调用Dao的接口 来获取Dao的数据
//1.调用dao,获取数据 List<Emp> empList = empDao.listEmp();
然后在写Controller
package com.itheima.controller; import com.itheima.pojo.Emp; import com.itheima.pojo.Result; import com.itheima.service.EmpService; import com.itheima.service.impl.EmpServiceA; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class EmpController { private EmpService empService = new EmpServiceA(); @RequestMapping("/listEmp") public Result list() { //1.调用service,获取数据 List<Emp> empList = empService.listEmp(); //3. 响应数据 return Result.success(empList); } }
黑马笔记
控制层:接收前端发送的请求,对请求进行处理,并响应数据
@RestController
public class EmpController {
//业务层对象
private EmpService empService = new EmpServiceA();@RequestMapping("/listEmp")
public Result list(){
//1. 调用service层, 获取数据
List<Emp> empList = empService.listEmp();//3. 响应数据
return Result.success(empList);
}
}
业务逻辑层:处理具体的业务逻辑
-
业务接口
//业务逻辑接口(制定业务标准)
public interface EmpService {
//获取员工列表
public List<Emp> listEmp();
}
业务实现类
//业务逻辑实现类(按照业务标准实现)
public class EmpServiceA implements EmpService {
//dao层对象
private EmpDao empDao = new EmpDaoA();@Override
public List<Emp> listEmp() {
//1. 调用dao, 获取数据
List<Emp> empList = empDao.listEmp();//2. 对数据进行转换处理 - gender, job
empList.stream().forEach(emp -> {
//处理 gender 1: 男, 2: 女
String gender = emp.getGender();
if("1".equals(gender)){
emp.setGender("男");
}else if("2".equals(gender)){
emp.setGender("女");
}//处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
String job = emp.getJob();
if("1".equals(job)){
emp.setJob("讲师");
}else if("2".equals(job)){
emp.setJob("班主任");
}else if("3".equals(job)){
emp.setJob("就业指导");
}
});
return empList;
}
}
数据访问层:负责数据的访问操作,包含数据的增、删、改、查
-
数据访问接口
//数据访问层接口(制定标准)
public interface EmpDao {
//获取员工列表数据
public List<Emp> listEmp();
}
数据访问实现类
//数据访问实现类
public class EmpDaoA implements EmpDao {
@Override
public List<Emp> listEmp() {
//1. 加载并解析emp.xml
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
System.out.println(file);
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
return empList;
}
}
三层架构的好处:
-
复用性强
-
便于维护
-
利用扩展
重启运行
总结:
当我们在前端发起请求之后 请求先达到Controller程序 Controller程序 只负责接收请求和响应数据 所以Controller程序 接收到请求之后就去调用Service的方法 Service层负责对逻辑的处理 然后要获取数据 Service又去调用Dao 由Dao程序负责数据的访问操作 去查询数据
然后在将查询到的数据返回给Service 然后Service得到数据之后 在对数据进逻辑处理
最终在将处理结果返回给Controller程序 最后Controller程序的结果就是处理完毕的结果 最终在将这个结果响应给前端 这样就完成三层架构的拆分