目录

运行截图

尚硅谷MVC设计模式项目3总结_子类

尚硅谷MVC设计模式项目3总结_数组_02

尚硅谷MVC设计模式项目3总结_java_03

目标,实现一个基于文本界面的《开发团队调度软件》

主要知识点

  1. 类的继承和多态
  2. 对象的值传递、接口
  3. static和final修饰符
  4. 特殊类的使用:包装类、抽象类、内部类
  5. 异常处理

软件设计结构

该软件有三个模块组成

尚硅谷MVC设计模式项目3总结_子类_04

  • view模块:为主控模块,负责菜单的显示和处理用户操作【页面显示和 用户操作】
  • service模块:为实体对象(Employee及其子类如程序员等)的管理模块,NameListService和TeamService类分别用各自的数组来管理公司员工和开发团队成员对象
  • domain模块:为Employee及其子类等JavaBean类所在的包

开发步骤

第一步-创建项目基本组件

尚硅谷MVC设计模式项目3总结_java_05

首先设计domain包下的两套结构 :设备Equipment及其子类 和员工employee及其子类

  1. 将几个工具类先复制到项目中
  • TSUtility.java
  • Data.java
  1. 创建Equipment接口,以及实现各子类代码
  • 子类:PC类、Printer类、NoteBook类
  1. 创建Employee类,以及实现各子类代码
  • Programmer类、Designer类、Architect类
  1. 检查代码的正确性
    第一步还是比较轻松的

第二步-实现service包中的类

尚硅谷MVC设计模式项目3总结_java项目实战_06

完成service包中的NameListService类和TeamService类的开发

属于是业务逻辑层了
NameListService类的功能如下:
功能:负责将Data中的数据封装到Employee[]数组中,同时提供相关操作Employee[]的方法。
说明:
employees用来保存公司所有员工对象
NameListService()构造器:
根据项目提供的Data类构建相应大小的employees数组
再根据Data类中的数据构建不同的对象,包括Employee、Programmer、Designer、Architect对象,以及相关联的Equipment子类的对象
将对象存放到数组中
Data类位于service包中

尚硅谷MVC设计模式项目3总结_java项目实战_07


TeamService类设计

尚硅谷MVC设计模式项目3总结_java项目实战_08

teamService设置完之后
设置最后一步,teamView的编写

domain模块包含了所有的实体类:

尚硅谷MVC设计模式项目3总结_子类_09

左边四个类,是多层继承关系
(java中不能多继承,可以多层继承)

Employee类及其子类的设计

尚硅谷MVC设计模式项目3总结_java_10

说明:

memberId用来记录成员加入开发团队后,在团队中的ID

枚举类
类里面有有限个对象,而且对象是确定的,status可以用枚举类

​Double.parseDouble(); Integer.parseInt(); 将其他变量转换为double或者int类型​

Data

data.java这个相当于一个数据库
里面包含EMPLOYEES员工信息
String[][]

NameListService类的设计

员工列表的业务逻辑

这个就是获得员工,获得指定员工,

尚硅谷MVC设计模式项目3总结_数组_11

employees:数组对象,就和int类型的数组对象一样

说明:

  • getAllEmployees()方法,获取当前所有员工,返回包含所有员工对象的数组
  • getEmployee(id:int)方法:获取指定ID的员工对象
  • 参数:指定员工的ID
  • 返回:指定员工对象
  • 异常:找不到指定的员工
  • 在Service子包下提供自定义异常类:TeamException
  • 另外,可以根据需要
  • 自行添加其他方法或者重载构造器

NameListService.java源码

package com.atguigu.team.service;

import com.atguigu.team.domain.*;

//可以把data下所有的静态结构全部都导过来
//这个导入静态包,真的要学一下
import static com.atguigu.team.service.Data.*;

public class NameListService { //
private Employee[] employees; //定义一个私有的employee数组,里面存放的好多个employee,比如int类型,也可以啊,int类型里面存放很多int数据

public NameListService() { //其构造函数

employees = new Employee[EMPLOYEES.length]; //数组的长度为data类中数据的长度,怎么还可以引入data类,设置为静态?
// employees = new Employee[data.EMPLOYEES.length];如果没有导入那个静态包,就要把data.加上
for (int i = 0; i < employees.length; i++) {//通过循环来赋值
// 获取通用的属性
int type = Integer.parseInt(EMPLOYEES[i][0]);
int id = Integer.parseInt(EMPLOYEES[i][1]);
String name = EMPLOYEES[i][2];
int age = Integer.parseInt(EMPLOYEES[i][3]);
double salary = Double.parseDouble(EMPLOYEES[i][4]);

//
Equipment eq;//只声明。不去处理
double bonus;
int stock;

switch (type) {
case EMPLOYEE:
employees[i] = new Employee(id, name, age, salary);
break;
case PROGRAMMER:
eq = createEquipment(i);
employees[i] = new Programmer(id, name, age, salary, eq);
break;
case DESIGNER:
eq = createEquipment(i);
bonus = Integer.parseInt(EMPLOYEES[i][5]);
employees[i] = new Designer(id, name, age, salary, eq, bonus);
break;
case ARCHITECT:
eq = createEquipment(i);
bonus = Integer.parseInt(EMPLOYEES[i][5]);
stock = Integer.parseInt(EMPLOYEES[i][6]);
employees[i] = new Architect(id, name, age, salary, eq, bonus,
stock);
break;
}
}
}

private Equipment createEquipment(int index) {
int type = Integer.parseInt(EQIPMENTS[index][0]);

switch (type) {
case PC:
return new PC(EQIPMENTS[index][1], EQIPMENTS[index][2]);
case NOTEBOOK:
int price = Integer.parseInt(EQIPMENTS[index][2]);
return new NoteBook(EQIPMENTS[index][1], price);
case PRINTER:
return new Printer(EQIPMENTS[index][1], EQIPMENTS[index][2]);
}
return null;
}
//获取所有员工,直接返回数组即可
public Employee[] getAllEmployees() {
return employees;
}
//获取指定员工
public Employee getEmployee(int id) throws TeamException {
for (Employee e : employees) {
if (e.getId() == id)
return e;
}
//自定义异常
throw new TeamException("该员工不存在");
}
}

获取指定id员工的代码解析
这里有个知识点

//得到其中一个员工的id
public Employee getEmployee(int id){

//两种写法
//通过for循环
// for (int i=0;i<employees.length;i++){
// if (employees[i].getId()==id){
// return employees[i];
// }
// }

//通过foreach循环
//根据id查找
for (Employee e:employees){
if (e.getId()==id){
return e;
}
}
}

​#​​== 和 equals() 的区别

==

  • 对于基本数据类型来说,​​==​​ 比较的是值。
  • 对于引用数据类型来说,​​==​​ 比较的是对象的内存地址。

记住:所有整型包装类对象之间值的比较,全部使用 equals 方法比较

尚硅谷MVC设计模式项目3总结_数组_12

equals和==区别

提到了,equals和==的区别,这个就是如果要调用对象.变量的大小比较,那么就用equals。
不然比较的是地址

尚硅谷MVC设计模式项目3总结_java项目实战_13

自定义一个异常类

一般自定义异常类就继承
runtimeException【运行时报错】
或者
exception【编译时报错】

package com.atguigu.team.service;

public class TeamException extends Exception {
static final long serialVersionUID = -33875169124229948L;

public TeamException() {
}

public TeamException(String message) {
super(message);
}

}
public Employee getEmployee(int id) throws TeamException {
for (Employee e : employees) {
if (e.getId() == id)
return e;
}
//自定义异常
throw new TeamException("该员工不存在");
}
}

单元测试

单元测试需要导包

import org.junit.Test;

employee
programmer
designer
architect每个类中的tostring重新写,用于格式展示数据

TeamService类的设计

获取团队所有成员
获取增加团队成员
移出团队成员

尚硅谷MVC设计模式项目3总结_java_14

功能:关于开发团队成员的管理:添加、删除等。
说明:

  • counter为静态变量,用来为开发团队新增成员自动生成团队中的唯一ID,即memberId。(提示:应使用增1的方式)
  • MAX_MEMBER:表示开发团队最大成员数
  • team数组:用来保存当前团队中各成员对象
  • total:记录团队成员的实际人数

TeamService.java源码

package com.atguigu.team.service;

import com.atguigu.team.domain.*;

//业务逻辑层
public class TeamService {
private static int counter = 1;//用于自动生成团队成员的memberId
private final int MAX_MEMBER = 5;//团队人数上限
private Programmer[] team = new Programmer[MAX_MEMBER];//保存当前团队成员
private int total = 0;//团队实际人数

public TeamService() {
}

//返回team中所有程序员构成的数组
public Programmer[] getTeam() {
Programmer[] team = new Programmer[total];

for (int i = 0; i < total; i++) {
team[i] = this.team[i];
}
return team;
}

//添加成员
public void addMember(Employee e) throws TeamException {
if (total >= MAX_MEMBER)
throw new TeamException("成员已满,无法添加");
if (!(e instanceof Programmer))
throw new TeamException("该成员不是开发人员,无法添加");
//一定不会出现ClassCastException这个异常,强制类型转换错误,因为上面已经过滤过了
Programmer p = (Programmer)e;
if (isExist(p))
throw new TeamException("该员工已在本团队中");
//if(p.getStatus().getNAME().equals("BUSY")) {
if("BUSY".equals(p.getStatus().getNAME())) {
//这种写法优于上面,因为上面增加了空指针异常的风险
throw new TeamException("该员工已是某团队成员");
}
// else if(p.getStatus().getNAME().equals("VOCATION")) {
else if("VOCATION".equals(p.getStatus().getNAME())) {
throw new TeamException("该员正在休假,无法添加");
}
// switch (p.getStatus()) {
// case BUSY :throw new TeamException("该员工已是某团队成员");
// case VOCATION:throw new TeamException("该员正在休假,无法添加");
// }
//获取team已有成员中架构师、设计师、程序员的人数
int numOfArch = 0, numOfDsgn = 0, numOfPrg = 0;
for (int i = 0; i < total; i++) {
if (team[i] instanceof Architect) numOfArch++;
else if (team[i] instanceof Designer) numOfDsgn++;
else if (team[i] instanceof Programmer) numOfPrg++;
}

//先判断架构师,因为其范围小
if (p instanceof Architect) {
if (numOfArch >= 1) throw new TeamException("团队中至多只能有一名架构师");

} else if (p instanceof Designer) {
if (numOfDsgn >= 2) throw new TeamException("团队中至多只能有两名设计师");

} else if (p instanceof Programmer) {
if (numOfPrg >= 3) throw new TeamException("团队中至多只能有三名程序员");
}

//添加到数组
p.setStatus(Status.BUSY);
p.setMemberId(counter++);
//将p(或e)添加到现有的team中
team[total++] = p;
}

//判断指定员工是否已经存在于现有开发团队中
private boolean isExist(Programmer p) {
for (int i = 0; i < total; i++) {
if (team[i].getId() == p.getId()) return true;
}
return false;
}

//删除指定memberId的程序员
public void removeMember(int memberId) throws TeamException {
int n = 0;
//找到指定memberId的员工,并删除
for (; n < total; n++) {
if (team[n].getMemberId() == memberId) {
team[n].setStatus(Status.FREE);
break;
}
}
//如果遍历一遍,都找不到,则报异常
if (n == total)
throw new TeamException("找不到该成员,无法删除");
//后面的元素覆盖前面的元素
// i=n+1; 即n的后一个元素
//这种不要死记硬背里面是什么,主要关键是看你里面怎么写
//看边界,就是最多可以到达哪里

for (int i = n + 1; i < total; i++) {
team[i - 1] = team[i];
}
//写法一:将最后一个位置置为空
// team[total-1]=null;
// total--;

//写法二:
team[--total] = null;

}//removeMember
}

尚硅谷MVC设计模式项目3总结_java_15

注意点:
这样可以忽略大小写

尚硅谷MVC设计模式项目3总结_数组_16

经典数组[i++]

就是显示完[i]后,然后i++

尚硅谷MVC设计模式项目3总结_java_17

判断团队中一个团队最多1个架构师,2个设计师,3个程序员,一个错误写法

尚硅谷MVC设计模式项目3总结_java项目实战_18

举个例子就明白了

假如团队中只有2名设计师Designer。然后此时来了一个架构师architect

执行第一句,前面为true后面为false。
会执行第二句 ,架构师也是设计师
所以就会出现bug,“团队中至多2名设计师的错误”

Java 实例 - instanceof 关键字用法

instanceof是java中的一个二元操作符,类似于==,>等操作符
作用是测试它的左边的对象是否是它右边的类的实例,返回boolean的数据类型

if (isExist(p))
throw new TeamException("该员工已在本团队中");

//if(p.getStatus().getNAME().equals("BUSY")) {

if("BUSY".equals(p.getStatus().getNAME())) {
//这种写法优于上面,因为上面增加了空指针异常的风险
throw new TeamException("该员工已是某团队成员");
}
//else if(p.getStatus().getNAME().equals("VOCATION")) {
else if("VOCATION".equals(p.getStatus().getNAME())) {
throw new TeamException("该员正在休假,无法添加");
}

退出方法的代码

case '4':
System.out.print("确认是否退出(Y/N):");
char yn = TSUtility.readConfirmSelection();
if (yn == 'Y')
loopFlag = false; //结束循环,程序执行完毕,就不能再执行了
break; //退出循环

do-while和while循环区别

do-while 循环,不管条件成立与否,都会执行一次,while循环可能一次也不执行

do {
//应该在每次都做1234选项时,先显示一下,所有员工,

//这个是初始菜单-------------
if (key != '1') {
//所有员工信息
listAllEmployees();
}
System.out.print("1-团队列表 2-添加团队成员 3-删除团队成员 4-退出 请选择(1-4):");
//这个是初始菜单-------------
//如果输入的是1,那么显示1,输入2,显示2,输入3,显示3,输入4显示4
//每执行完一个结果,那么就按回车键继续,然后再显示初始菜单
key = TSUtility.readMenuSelection();
System.out.println();
switch (key) {
case '1':
//显示团队信息
listTeam();
break;
case '2':
// 添加成员到团队
addMember();
break;
case '3':
// 从团队中删除指定id的成员
deleteMember();
break;
case '4':
System.out.print("确认是否退出(Y/N):");
char yn = TSUtility.readConfirmSelection();
if (yn == 'Y')
loopFlag = false; //结束循环,程序执行完毕,就不能再执行了
break; //退出循环
}
} while (loopFlag);


代码如下:

private void listAllEmployees() {
System.out.println("\n-----------------开发团队调度软件-----------------\n");
Employee[] emps = listSvc.getAllEmployees();
if (emps.length == 0) {
System.out.println("没有客户记录!");
} else {
System.out.println("ID\t姓名\t年龄\t工资\t职位\t状态\t奖金\t股票\t领用设备");
}
for (Employee e : emps) {
System.out.println(" " + e);
}
System.out.println("----------------------------------------------------");
}

难点:
listSvc.getAllEmployees();
这个调用了

NameListService,这个类中的
getAllEmployees()方法
然后,NameListService中的getAllEmployees()方法
是直接返回employees,然后NameListService的构造方法将员工信息都写入到employee中

TeamView中添加开发团队成员

private void addMember() {
System.out.println("---------------------添加成员---------------------");
System.out.print("请输入要添加的员工ID:");
//输入id,添加员工
int id = TSUtility.readInt();
//此时,给的是id,要添加员工
try {
//获取员工对象,此时可能出现异常,比如,id不存在,对象已经添加过了
Employee e = listSvc.getEmployee(id);
teamSvc.addMember(e);
//获取员工对象

System.out.println("添加成功");

} catch (TeamException e) {
System.out.println("添加失败,原因:" + e.getMessage());
}
// 按回车键继续...
TSUtility.readReturn();
}

TeamView中删除开发团队成员

// 3从团队中删除指定id的成员
private void deleteMember() {
System.out.println("---------------------删除成员---------------------");
System.out.print("请输入要删除员工的TID:");
int id = TSUtility.readInt();
System.out.print("确认是否删除(Y/N):");
char yn = TSUtility.readConfirmSelection();
if (yn == 'N')
return;
try {
teamSvc.removeMember(id);
System.out.println("删除成功");
} catch (TeamException e) {
System.out.println("删除失败,原因:" + e.getMessage());
}
// 按回车键继续...
TSUtility.readReturn();
}

总结

for循环和foreach相互转换
for( ; ; ) 可以什么都不加

枚举类:status
类中有限个对象,且对象是确定的
status。将构造器私有化,这样就不允许其在外面造对象了

二维数组代替数据库
instanceof 关键字用法
instanceof是java中的一个二元操作符,类似于==,>等操作符
作用是测试它的左边的【对象】是否是它右边的【类】的实例,返回boolean的数据类型
比如

//获取team已有成员中架构师、设计师、程序员的人数
int numOfArch = 0, numOfDsgn = 0, numOfPrg = 0;
for (int i = 0; i < total; i++) {
if (team[i] instanceof Architect) numOfArch++;
else if (team[i] instanceof Designer) numOfDsgn++;
else if (team[i] instanceof Programmer) numOfPrg++;
}

在定义接口时,jdk7,里面只有抽象方法
jdk8加入了默认方法和静态方法