一、基本介绍
该项目是尚硅谷中JavaSE项目三,涉及内容有继承、异常、多态、接口等知识。
1、主界面
主界面如上图所示,主要关注点:职位、状态、奖金、股票、领用设备。
2、团队列表
团队成员现在包含ID是2的职员,具体显示属性和主界面也有所不同。
3、代码模块
domain中定义的职员和设备信息,其中Employee是Programmer的父类,Programmer是Designer的父类,Designer是Architect的父类,依次继承;Equipment是接口类,NoteBook、PC、Printer是实现接口的类。
junit包含单元测试类,可以不关注。
service中定义的有数据,相应的处理逻辑和异常处理。
view中定义的有与用户交互的界面功能,提供输入的功能函数TSUtility。
二、具体分析
集中介绍其中几个重要的类和方法。
1、Programmer类
public class Programmer extends Employee{
private int memberId; // 在开发团队中的id
// FREE,BUSY,VOCATION三种状态,表示程序员现在的状态
// 默认是FREE状态。
private Status status = Status.FREE;
// equipment表示设备
private Equipment equipment;
public Programmer() {
super();
}
public Programmer(int id, String name, int age, double salary, Equipment equipment) {
super(id, name, age, salary);
this.equipment = equipment;
}
public int getMemberId() {
return memberId;
}
public void setMemberId(int memberId) {
this.memberId = memberId;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public Equipment getEquipment() {
return equipment;
}
public void setEquipment(Equipment equipment) {
this.equipment = equipment;
}
public String toString(){
return getDetails() + "\t程序员\t" + status + "\t\t\t\t\t" +
equipment.getDescription();
}
public String getDetailsForTeam(){
return memberId + "/" + getId() + "\t\t" + getName() + "\t" + getAge() + "\t\t" +
getSalary() + "\t" + "程序员";
}
}
Programmer继承Employee类,特有属性memberId,该属性作为团队信息的关键字和Id一样是唯一的,status具有三种状态,FREE、BUSY、VOCATION。
toString方法进行重写,是为了在主菜单输出职员信息时可以统一,toString内的getDetails是在Employee中定义的,也是输出它的基本属性。
getDetailsForTeam是针对开发团队信息输出格式。
2、NoteBook类
public class NoteBook implements Equipment{
private String model;
private double price; // 价格
public NoteBook() {
}
public NoteBook(String model, double price) {
this.model = model;
this.price = price;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String getDescription() {
return model + "(" + price + ")";
}
}
NoteBook实现Equipment接口,Equipment接口中只有getDescription方法。
3、Data类
public class Data {
// 10,11,12,13表示程序员的类型
public static final int EMPLOYEE = 10;
public static final int PROGRAMMER = 11;
public static final int DESIGNER = 12;
public static final int ARCHITECT = 13;
// 21,22,23代表配备的电脑型号
public static final int PC = 21;
public static final int NOTEBOOK = 22;
public static final int PRINTER = 23;
// EMPLOYEE: 10,ID,NAME,AGE,SALARY
// PRIGRAMMER: 11,ID,NAME,AGE,SALARY
// DESIGNER: 12,ID,NAME,AGE,SALARY,BONUS
// ARCHITECT: 13,ID,NAME,AGE,SALARY,BONUS,STOCK
// 上面4个也是依次往下继承
// EMPLOYEES存储职员信息,不同类型职员它的属性不同,例如,架构师有薪水、奖金和股票。
public static final String[][] EMPLOYEES = {
{"10", "1", "马云 ", "22", "20000"},
{"13", "2", "马化腾", "23", "20000", "10000", "10000"},
{"11", "3", "李彦宏", "24", "20000"},
{"11", "4", "刘强东", "25", "20000"},
{"12", "5", "雷军 ", "26", "20000", "10000"},
{"11", "6", "任志强", "27", "20000"},
{"12", "7", "柳传志", "28", "20000", "10000"},
{"13", "8", "杨云庆", "29", "20000", "10002", "20000"},
{"12", "9", "史玉柱", "22", "20000", "20000"},
{"11", "10", "丁磊 ", "22", "20000"},
{"11", "11", "张朝阳", "25", "8000"},
{"12", "12", "杨致远", "27", "10000", "20000"}
};
// EQUIPMENTS是职员对应相应的设备。
public static final String[][] EQUIPMENTS = {
{},
{"22", "联想T4", "6000"},
{"21", "戴尔", "NEC17寸"},
{"21", "戴尔", "三星17寸"},
{"23", "佳能2900", "激光"},
{"21", "华硕", "三星17寸"},
{"21", "华硕", "三星17寸"},
{"23", "爱普尔20K", "针式"},
{"22", "惠普m6", "5800"},
{"21", "戴尔", "NEC17寸"},
{"21", "华硕", "三星17寸"},
{"22", "惠普m6", "5800"}
};
}
没有用到数据库,暂时在类中创建这些数据,EQUIPMENTS是对应员工的设备类型。
4、NameListService类
public class NameListService {
private Employee[] employees;
public NameListService(){
// 根据Data类构建相应大小的employees数组
// 再根据Data类中的数据构建不同的对象,包括Employee、Programmer、Designer
// Architect
// 根据EMPLOYEES来建立空间
employees = new Employee[EMPLOYEES.length];
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 equipment;
double bonus;
int stock;
switch (type){
case EMPLOYEE:
employees[i] = new Employee(id, name, age, salary);
break;
case PROGRAMMER:
// 找第i个职员的设备信息
equipment = creatEquipment(i);
employees[i] = new Programmer(id, name, age, salary, equipment);
break;
case DESIGNER:
// 找第i个职员的设备信息
equipment = creatEquipment(i);
bonus = Double.parseDouble(EMPLOYEES[i][5]);
employees[i] = new Designer(id, name, age, salary, equipment, bonus);
break;
case ARCHITECT:
equipment = creatEquipment(i);
bonus = Double.parseDouble(EMPLOYEES[i][5]);
stock = Integer.parseInt(EMPLOYEES[i][6]);
employees[i] = new Architect(id, name, age, salary, equipment, bonus, stock);
break;
default:
break;
}
}
}
// 获取指定位置员工的设备。
public Equipment creatEquipment(int index){
int type = Integer.parseInt(EQUIPMENTS[index][0]);
switch (type){
case PC: // 21
return new PC(EQUIPMENTS[index][1], EQUIPMENTS[index][2]);
case NOTEBOOK:
return new NoteBook(EQUIPMENTS[index][1], Double.parseDouble(EQUIPMENTS[index][2]));
case PRINTER:
return new Printer(EQUIPMENTS[index][1], EQUIPMENTS[index][2]);
default:
break;
}
return null;
}
// 获取所有Employee
public Employee[] getAllEmployees(){
return employees;
}
// 获取某个id的职员
// 有可能id找不到,抛出异常
public Employee getEmployee(int id) throws TeamException{
for (Employee employee : employees) {
if (employee.getId() == id) {
return employee;
}
}
// 抛出异常
throw new TeamException("找不到指定的职员");
}
}
构造函数中将Data类中的数据,存储在Employee数组中,根据职员职位不同,new里面的信息也不相同。设备信息的创建也是根据型号的不同new不同实现Equipment接口的子类进行返回。
getAllEmployees方法是返回创建的职员信息。
getEmployee方法根据职员id好来查找相应的员工信息,如果找不到throw一个异常对象,然后用throws进行异常处理。
5、TeamService类
public class TeamService {
private static int counter = 1; // 给memberid赋值
private static final int MAX_MEMBER = 5; // 限制开发团队的人数
// 开发团队都必须是程序员以上的级别。
private Programmer[] team = new Programmer[MAX_MEMBER]; // 保存开发成员
private int total; // 记录开发团队的实际人数
public TeamService() {
}
// 获取开发团队中的所有成员
public Programmer[] getTeam(){
Programmer[] team = new Programmer[total];
for(int i = 0; i < team.length; ++i){
team[i] = this.team[i];
}
return team;
}
// 将指定的员工添加到团队中
/*
限制条件:
1、成员已满,无法添加
2、该成员不是开发人员,无法添加
3、该成员已在本开发团队中
4、该成员已是某团队成员
5、团队中至多只能有一名架构师
6、团队中至多只能有两名设计师
7、团队中至多只能有三名程序员
*/
public void addMember(Employee e) throws TeamException{
if(total >= MAX_MEMBER){
throw new TeamException("成员已满,无法添加");
}
// 该成员不是程序员
if(!(e instanceof Programmer)){
throw new TeamException("该成员不是开发人员,无法添加");
}
// e肯定是一个programmer,所以它也可以调用方法getId或者getMemberId来进行比较。
if(isExist(e)){
throw new TeamException("该成员已在本开发团队中");
}
// 判断状态
Programmer programmer = (Programmer) e;
if("BUSY".equals(programmer.getStatus().getNAME())){
throw new TeamException("该成员已是某团队成员");
}else if("VOCATION".equals(programmer.getStatus().getNAME())){
throw new TeamException("该成员正在休假,无法添加");
}
// 先看团队里几个架构师、设计师、程序员
int numOfArch = 0, numOfDes = 0, numOfPro = 0;
for(int i = 0; i < total; ++i){
if(team[i] instanceof Architect){
numOfArch++;
}else if(team[i] instanceof Designer){
numOfDes++;
}else if(team[i] != null) numOfPro++;
}
if(programmer instanceof Architect){
if(numOfArch >= 1) throw new TeamException("团队中至多只能有一名架构师");
}else if(programmer instanceof Designer){
if(numOfDes >= 2) throw new TeamException("团队中至多只能有两名设计师");
}else if(numOfPro >= 3) throw new TeamException("团队中至多只能有三名程序员");
programmer.setStatus(Status.BUSY);
programmer.setMemberId(counter++);
// 前面这两句放后面也行,因为指向是一样的。
team[total++] = programmer;
}
private boolean isExist(Employee e){
for(int i = 0; i < total; ++i){
if(team[i].getId() == e.getId()){
return true;
}
}
return false;
}
// 从团队中删除成员
public void removeMember(int memberId) throws TeamException{
int i;
for(i = 0; i < total; ++i){
if(team[i].getMemberId() == memberId){
team[i].setStatus(Status.FREE);
break;
}
}
if(i == total) throw new TeamException("找不到指定memberId的职员,删除失败");
// 删除元素,覆盖前一个元素
for(int j = i + 1; j < total; ++j){
team[j - 1] = team[j];
}
team[--total] = null;
}
}
首先明确其实对团队成员信息的增加、删除、显示。
getTeam方法获取当前在团队中的员工信息。
addMember方法将员工信息加入,有很多种限制条件需要去考虑,例如员工职位必须是Programmer以上才行,而且最后如果成功将员工信息加入团队中,需要将其状态设置为BUSY。
removeMember方法按照memberId查找团队中成员信息,如果查找到了,将其状态设置为FREE,而且将其后面的元素往前移动一位,最后一个数组元素设置为null;如果查找不到,那么则throw一个异常信息。
6、TeamException类
public class TeamException extends Exception{
// 提供uid
static final long serialVersionUID = -3282772728L;
public TeamException(){
}
public TeamException(String msg){
super(msg);
}
}
自定义类,将throw过来的msg传给父类,然后在具体的方法通过进行try-catch,可以用getMessage来打印相应的失败原因信息。
7、TeamView类
public class TeamView {
private NameListService listService = new NameListService();
private TeamService teamService = new TeamService();
public void enterMainMenu(){
boolean loopflag = true;
char menu;
listAllEmployees();
while(loopflag){
System.out.println("1-团队列表 2-添加团队成员 3-删除团队成员 4-退出");
System.out.print("请选择(1-4)");
menu = TSUtility.readMenuSelection();
if(menu != '1' && menu != '4')
listAllEmployees();
switch (menu){
case '1':
getTeam();
break;
case '2':
getTeam();
addMember();
break;
case '3':
getTeam();
deleteMember();
break;
case '4':
System.out.print("是否要退出(Y/N):");
char isExit = TSUtility.readConfirmSelection();
if(isExit == 'Y')
loopflag = false;
break;
}
}
}
// 显示所有的员工信息
private void listAllEmployees(){
System.out.println("------------------------开发团队调度软件---------------------------");
Employee[] employees = listService.getAllEmployees();
if(employees == null || employees.length == 0){
System.out.println("该公司中没有任何员工信息");
}else{
System.out.println("ID\t姓名\t\t年龄\t工资\t\t职位\t\t状态\t\t奖金\t\t股票\t\t领用设备");
for(Employee employee: employees){
System.out.println(employee);
}
}
System.out.println("-----------------------------------------------------------------");
}
private void getTeam(){
System.out.println("------------------------团队成员列表---------------------------");
Programmer[] team = teamService.getTeam();
if(team == null || team.length == 0){
System.out.println("开发团队没有成员!");
}else{
System.out.println("TID/ID\t姓名\t\t年龄\t\t工资\t\t职位\t\t奖金\t\t股票");
for(int i = 0; i < team.length; ++i){
// 不能直接使用toString
// 需要重写
System.out.println(team[i].getDetailsForTeam());
}
}
System.out.println("-------------------------------------------------------------");
}
private void addMember(){
System.out.println("------------------------添加成员---------------------------");
System.out.print("请输入要添加的员工ID:");
int id = TSUtility.readInt();
try{
Employee employee = listService.getEmployee(id);
teamService.addMember(employee);
System.out.println("添加成功!");
}catch (TeamException e){
System.out.println("添加失败" + e.getMessage());
}
}
private void deleteMember(){
System.out.println("------------------------删除成员---------------------------");
System.out.print("请输入要删除的员工TID:");
int memberId = TSUtility.readInt();
System.out.print("确认是否删除(Y/N):");
char isDelete = TSUtility.readConfirmSelection();
if(isDelete == 'Y'){
try{
teamService.removeMember(memberId);
System.out.println("删除成功!");
}catch (TeamException e){
System.out.println("删除失败!原因是:" + e.getMessage());
}
}
}
public static void main(String[] args) {
TeamView teamView = new TeamView();
teamView.enterMainMenu();
}
}
listAllEmployees方法显示员工信息。
getTeam方法显示团队成员信息。
3、总结
通过TeamView进行交互,NameListService是对于员工信息的操作,TeamService是对团队成员的操作,domain中的类就是一些基本的职员信息类和设备信息类,采用继承、实现接口。将一些暂时不处理的异常抛出,用throws异常处理方式,然后调用相应方法时再用catch进行处理。