文章目录
- 前言
- 一、人员管理系统概述
- 二、分层
- 2. 1 三层架构概述
- 2. 2 为什么分层
- 2. 3 人员管理系统分层
- 三、分包
- 2.1 分包思想概述
- 2.2 包的概述
- 2.3 包的注意事项
- 2.4 类与类之间的访问
- 四、学生管理系统
- 3.1 需求说明
- 3.2 实现步骤
- 3.3 具体实现
- 五、老师管理系统
- 总结
前言
本文章下的代码中有一些个人在学习过程中的注解,可以参考理解,说法有误可指正。
一、人员管理系统概述
基于分层思想去构建一个在控制台运行的管理系统,实现对人员的简易管理。
- [ 人员管理系统]
- 学生管理系统
对学生信息进行管理
完成对学生信息的增删查改的操作 - 老师管理系统
对老师信息进行管理
完成对老师信息的增删查改的操作
二、分层
2. 1 三层架构概述
三层架构 (3-tier architecture) : 在软件体系架构中,自上而下将整个业务应用划分为三层:
- 表示层(User lnterface layer): 主要是指与用户交互的界面。用于接收用户输入的数据和显示处理后用户需要的数据。
- 业务逻辑层(Business Logic Layer): 主要实现业务逻辑。业务逻辑具体包含: 验证、计算、业务规则等等,UI层(表示层)和DAL层(数据访问层)之间的桥梁。
- 数据访问层(Data acess layer): 主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。
2. 2 为什么分层
分层思想的目的即为了实现高内聚低耦合。
内聚:是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事,它描述的是模块内的功能联系。
耦合: 是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。
**高内聚低耦合:**是软件工程中的概念,是判断软件设计好坏的标准,主要用于程序的面向对象的设计,主要看类的内聚性是否高,耦合度是否低。(高内聚:模块的聚合度高,低耦合:模块之间的关联性低)
高内聚低耦合目的是使程序模块的可重用性、移植性大大增强。
通常程序结构中各模块的内聚程度越高,模块间的耦合程度就越低。
低内聚高耦合如下图:
高内聚低耦合如下图:
- [ 总结:]
- 高内聚(模块的规划和排列很整齐)低耦合(模块之间没有杂乱的排线,只通过引脚的联系)
2. 3 人员管理系统分层
- Student类:标准学生类,封装键盘录入的学生信息(id,name,age,birthday)
- Student Dao类 Dao :(Data Access Object 缩写) 用于访问存储数据的数组或集合;——数据访问层
- Student Service类:用来进行业务逻辑的处理(例如: 判断录入的id是否存在);——业务逻辑层
- Student Controller类:和用户打交道(接收用户需求,采集用户信息,打印数据到控制台);——表示层
三、分包
2.1 分包思想概述
如果将所有的类文件都放在同一个包下,不利于管理和后期维护,所以,对于不同功能的类文件,可以放在不同的包下进行管理。
2.2 包的概述
- 包
本质上就是文件夹 - 创建包
多级包之间使用"."进行分割- 包的命名规则:字母都是小写
2.3 包的注意事项
- package语句必须是程序的第一条可执行的代码
- package语句在一个iava文件中只能有一个
- package声明表示该类的所属关系,如果没有package则默认表示无包名
- 所有包的操作都由idea去完成
2.4 类与类之间的访问
- 同一个包下的访问
不需要导包,直接使用即可 - 不同包下的访问
- import 导包后访问;
- 通过全类名 (包名 +类名) 访问注意: import、package 、class 三个关键字的摆放位置存在顺序关系。
- package 必须是程序的第一条可执行的代码import 需要写在 package 下面class 需要在 import 下面:
四、学生管理系统
3.1 需求说明
- 添加学生:键盘录入学生信息(id,name,age,birthday)使用数组存储学生信息,要求学生的id不能重复
- 删除学生:键盘录入要删除学生的id值,将该学生从数组中移除,如果录入的id在数组中不存在,需要重新录入
- 修改学生:键盘录入要修改学生的id值和修改后的学生信息将数组中该学生的信息修改,如果录入的id在数组中不存在,需要重新录入
- 查询学生: 将数组中存储的所有学生的信息输出到控制台
3.2 实现步骤
- 环境搭建实现步骤
包(com.wedu.staff.manager) | 存储的类 | 作用 |
com.staff.manager.domain | Student.java | 封装学生信息 |
com.staff.manager.dao | StudentDao.java | 访问存储数据的数组,进行增删改查 (库管) |
.service | StudentService.java | 业务的逻辑处理 (业务员) |
.controller | StudentController.java | 和用户打交道 (客服接待) |
.entry | StaffManagerEntry.java | 程序的入口类,提供一个main方法 |
- 菜单搭建实现步骤
- 需求
- XX人员管理系统菜单搭建
- 学生管理系统菜单搭建
- 实现步骤
- 展示欢迎页面,用输出语句完成主界面的编写
- 获取用户的选择,用Scanner实现键盘录入数据
- 根据用户的选择执行对应的操作,用switch语句完成操作的选择
3.3 具体实现
- [ 分包] 如图
- [ 分层] 如图
- 菜单界面即功能选择
import java.util.Scanner;
//人员管理系统的交互界面
//程序主函数的入口
public class StaffManagerEntry {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("-------欢迎来到人员管理系统-------");
System.out.println("请选择想进行的操作(1-3):");
System.out.println("1.学生管理 2.教师管理 3.退出");
String choice = sc.next();
switch (choice) {
case "1":
//调用学生管理系统
//创建一个新的学生表示层对象——新的StudentController对象
StudentController studentController = new StudentController();
//用新的学生表现层对象调用StudentController类中的start()方法
studentController.start();
break;
case "2":
//调用老师管理系统,与学生管理系统同理
TeacherController teacherController = new TeacherController();
teacherController.start();
break;
case "3":
//退出
//另一种方法退出死循环,调用System里的一个exit()方法
System.out.println("欢迎再次使用!");
System.exit(0);//让JVM停止运行
break;
default:
System.out.println("您的输入有误,请重新输入!!");
}
}
}
}
进入学生管理系统界面与主菜单差不多,但会在相应功能选择处调用相应的方法,后面会
switch (choice) {
case "1":
//调用添加学生的方法
addStudent();
break;
case "2":
//调用删除学生的方法
deleteStudentById();
break;
case "3":
//调用修改学生的方法
updateStudent();
break;
case "4":
//调用查看学生的方法
findAllStudent();
break;
case "5":
//退出
//此时不能调用System里的exit()方法来退出程序,因为我们目的只是为了退出学生管理系统的模块,而不是退出整个人员管理系统
System.out.println("欢迎再次使用!");
break StuLoop;//退出学生管理系统
default:
System.out.println("您的输入有误,请重新输入!!");
}
- 添加功能及添加功能优化(判断id是否存在)实现步骤
通过addStudent()方法
需要利用三层架构,在三个层面都去利用到addStudent()这个方法来实现我们的这个操作
- [表示层 ]
public void addStudent() {
String id;
//提示用户键盘录入想要添加的学生的各项信息
System.out.println("请输入学生信息:");
while (true) {
System.out.println("输入学生的学号:");
id = sc.next();
//判断是否有重复的学生id
//创建一个新的业务逻辑层对象,来传递学生的id进行逻辑判断
boolean res = studentService.isExists(id);//用res接收业务逻辑层中IsExists()方法运行结束的返回值
//IsExists()方法:调用数据访问层中的findAllStudent()方法获取到学生数组
//使id与学生数组中的id进行比较,从而判断id是否存在,存在则提示用户重新输入,若不存在则继续进行添加操作
//判断用户录入的id在数组中是否存在
if (res) {//存在-true
System.out.println("您输入的学号已存在,请重新输入:");
} else {//不存在-false
break;//跳出死循环,继续进行添加操作
}
}
//
Student student =inputStudentinfo(id);
//创建一个新的业务逻辑处理(StudentService)的对象
//在StudentService类中写一个针对添加学生的addStudent()方法,来对新的学生对象student作出一些逻辑处理,并做一些对接
//创建一个新的业务逻辑层对象,来传递学生对象,从而进行添加操作
StudentService studentService = new StudentService();
boolean result = studentService.addStudent(student);
if (result) {
System.out.println("添加成功!!");
} else {
System.out.println("添加失败!!");
}
}
- [业务逻辑层 ]
public boolean isExists(String id) {
Student[] students=studentDao.findAllStudent();//调用数据访问层中获取学生数组的方法
//findAllStudent()该方法应该返回一个数组,用student接收
boolean res=false;//定义一个boolean类型的变量res初始为false
for (int i = 0; i < students.length; i++) {
//如果添加第一个学生时,此时学生数组为null,用户输入的id与null是无法比较的,因此会出现空指针异常
//解决:加一个条件判断,判断新的
if(students[i]!=null) {
if (students[i].getId().equals(id)) {//判断存不存在相同id
res = true;//若学生数组存在相同id,就改变res的值为true
break;//终止循环,执行循环外的语句
}
}
}
return res;
}
//添加学生在业务逻辑处的方法addStudent
public boolean addStudent(Student student){
//判断id是否存在——在下面IsExists()方法中实现
//将接受到的Student类中student学生对象传给数据访问层StudentDao类
//等待StudentDao类保存数据并返回成功与否(用Boolean值进行接收)
//将其结果(boolean值)又再返回给表示层StudentController类
boolean result=studentDao.addStudent(student);
return result;
}
- [数据访问层 ]
public boolean addStudent(Student student){
//创建一个容器,用来存储被传进来的学生对象,并进行添加操作
//进行添加操作首先:因为数组中没有存放学生对象时,里面的初始值都为null
// 要想添加学生对象,得先判断数组中还有没有空间可以存放,因此利用null值来判断
// 如果数组中找得到为null的值,就把该值的下标索引赋给index变量
// 进而实现添加操作
int index=-1;//定义一个用来判断数组students中还有没有null值的变量
//遍历数组找第一个null值,并将该值的下标索引赋给index变量
for (int i = 0; i < students.length; i++) {
if (students[i] == null) {
index = i;
break;//如果不加break就相当于添加学生时是从数组的末尾开始存入数据,因此打印数据时会从最后一个数据开始打印;
//反之从数组的第一个位置存入,打印时的顺序就是学号的顺序
}
}
//对index进行判断,如果不为-1,才将学生对象的信息存储到数组里面,并返回相应的Boolean类型的结果
if(index==-1){
System.out.println("暂无空间存放学生,请稍后再试!");
return false;
}else {
students[index]=student;
//boolean result = true;
return true;
}
}
- 查询功能实现步骤
- [表示层 ]
//查看学生
public void findAllStudent() {
Student[] students = studentService.findAllStudent();
if (students == null) {
System.out.println("查无信息!!");
return;
} else {
System.out.println("学号\t\t姓名\t\t年龄\t\t生日");
for (int i = 0; i < students.length; i++) {
Student stu = students[i];
if(stu!=null){
System.out.println(stu.getId() + "\t" + stu.getName() + "\t" + stu.getAge() + "\t" + stu.getBirthday());
}
}
}
}
- [业务逻辑层 ]
public Student[] findAllStudent() {
//调用数据访问层studentDao类中的findAllStudent()方法获取学生数组
//并新建一个学生数组(在StudentService的findAllStudent()方法中),用于接收从Dao中获取到的学生数组的数据
Student[] students=studentDao.findAllStudent();
boolean res=false;//定义一个布尔类型的变量res,用来判断数组中存不存在学生信息,假设数组中没有学生数据,则返回null
for (int i = 0; i < students.length; i++) {
//判断该学生数组中存不存在数据,若存在数据则令res=true,只要找到存在一条数据,即可证明就可以跳出循环进行下一步判断
if(students[i]!=null){
res=true;
break;
}
}
//判断res的值,存在数据——true,并返回学生数组给表示层,反之——false,就返回null值给表示层
if (res){
return students;
}else {
return null;
}
}
- [数据访问层 ]
//获取所有学生数组,用于被其他层调用进行相应的操作:查询和判断比较
public Student[] findAllStudent() {
return students;
}
- 删除功能实现步骤
- [表示层 ]
public void deleteStudentById() {
String delId=inputStudentId();
//调用业务逻辑层中的方法进行删除学生
studentService.deleteStudentById(delId);
System.out.println("删除成功!");
}
- [业务逻辑层 ]
public void deleteStudentById(String delId) {
studentDao.deleteStudentById(delId);
}
- [数据访问层 ]
//进行删除操作,找到与用户录入id相同的学生id的索引位置,将其位置的数据重置为null,就完成了删除
public void deleteStudentById(String delId) {
int deleteindex=getIndex(delId);//将查找学生id的功能另写一个方法,通过方法调用实现,获取到id在数组中索引的位置
if(deleteindex!=-1){
students[deleteindex]=null;
}
}
- 修改功能实现步骤
- [表示层 ]
public void updateStudent() {
String updateId=inputStudentId();
//进行修改操作
//调用录入学生的信息的方法inputStudentinfo(),创建新的学生对象接收方法的返回值
Student updatestudent=inputStudentinfo(updateId);
//调用业务层的方法updateStudent(),修改学生并提示修改成功
studentService.updateStudent(updateId,updatestudent);
System.out.println("修改成功!");
}
- [业务逻辑层 ]
public void updateStudent(String updateId, Student updatestudent) {
studentDao.updateStudent(updateId,updatestudent);
}
- [数据访问层 ]
public void updateStudent(String updateId, Student updatestudent) {
int updateindex=getIndex(updateId);//调用查找id索引值的方法,找到需要修改的学生id的索引值
if(updateindex!=-1){
students[updateindex]=updatestudent;//使用传入进来的新的学生对象updatestudent进行替换
}
}
- 系统优化
- 把updateStudent()方法和deleteStudentById()方法中录入学生id代码抽取到一个方法(inputStudentld)中
- 该方法的主要作用就是录入学生的id,方法的返回值为String类型
//用户录入学生id,返回一个String类型的id值
private String inputStudentId() {
String id;
while (true){
System.out.println("请输入学生的学号:");
id= sc.next();
boolean res=studentService.isExists(id);
if(res){//res——true:存在,继续进行操作,跳出死循环(如果用户输入的学号不存在,为了能让用户重新输入)
break;
}else {//res——false:不存在,提示用户重新输入,直到判断出用户录入的id存在我们的学生数组中
System.out.println("您输入的id不存在,请重新输入!");
}
}
return id;
}
- 把addStudent()和updateStudent()中录入学生信息的代码抽取到一个方法(inputStudentinfo)中
- 该方法的主要作用就是录入学生的信息,并封装为学生对象,方法的返回值为Student类型
//录入学生的信息的方法inputStudentinfo(),并封装为学生对象并且返回
private Student inputStudentinfo(String id) {
//要先录入新的学生信息,并封装成学生对象(便于传输操作,一个一个信息修改的话比较麻烦也繁琐)
//返回学生对象
System.out.println("输入学生的姓名:");
String name = sc.next();
System.out.println("输入学生的年龄:");
String age = sc.next();
System.out.println("输入学生的生日:");
String birthday = sc.next();
Student student=new Student(id,name,age,birthday);
return student;
}
五、老师管理系统
与学生管理系统同理,可以自己手动实现一下,更能初步的感受三层架构的简单用法,构建自己的分包分层思想
总结
对JAVASE的学习有更新的认识,初步了解了三层架构和面向对象的思想,后期依据面向对象的三大特征会对该系统进行改进。