项目需求分析
- 根据给定的数据创建公司部分员工列表;
- 基于现有的公司成员,组建一个开发团队;
- 展示出开发团队成员有哪些,并实现增加、删除操作;
- 开发团队的任职各有不同。
如果添加操作失败,则需要提示信息:
失败信息包含以下几种:
– 成员已满,无法添加
– 该成员不是开发人员,无法添加
– 该成员已在本开发团队中
– 该员工已是某团队成员
– 该成员正在休假,无法添加
– 团队中至多只能由一名架构师
– 团队中至多只能由两名设计师
– 团队中至多只能由三名程序员
软件设计结构
- TeamView 主控模块,负责菜单的显示和处理用户操作
- service(图中间三个大类)为实体对象(Employee及其子类)的管理模块,NameListService和TeamService类分别用各自的数组来管理公司员工和开发团队成员对象
- Employee类中还有程序员、设计师、架构师等子类。
工具类代码块
TSUtility类的解释:通过调用此类,可以实现键盘的访问。该类提供了以下静态方法
public static char readMenuSelection()
用途:该方法读取键盘,如果用户键入’1’-‘4’中任意字符,则方法返回。返回值为用户键入字符
public static void readReturn()
用途:该方法提示并等待,直到用户按回车键结束后返回。
public static int readInt()
用途:该方法从键盘读取一个长度不超过2位的整数,并将其作为方法的返回值。
public static char readConfirmSelection()
用途:从键盘读取’Y’或’N’。并将其作为方法的返回值。
package item_3_sgg;
import java.util.*;
/*
* @Description 项目中提供了TSUtility.java类,可用来方便地实现键盘访问。
*/
public class TSUtility {
private static Scanner scanner =new Scanner(System.in);
/*
* @Description 该方法读取键盘,如果用户键入'1'-'4'中任意字符,则方法返回。返回值为用户键入字符
*/
public static char readMenuSelection() {
char c;
for(;;) {
String str=readKeyBoard(1,false);
c=str.charAt(0);
if(c!='1'&&c!='2'&&
c!='3'&&c!='4') {
System.out.print("选择错误,请重新输入:");
}else break;
}
return c;
}
/*
* @Description 该方法提示并等待,直到用户按回车键结束后返回。
*/
public static void readReturn() {
System.out.print("按回车键继续....");
readKeyBoard(100,true);
}
/*
* @Description 该方法从键盘读取一个长度不超过2位的整数,并将其作为方法的返回值。
*/
public static int readInt() {
int n;
for(;;) {
String str=readKeyBoard(2,false);
try {
n=Integer.parseInt(str);
break;
}catch(NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/*
* @Description 从键盘读取'Y'或'N'。并将其作为方法的返回值。
*/
public static char readConfirmSelection() {
char c;
for(;;) {
String str =readKeyBoard(1,false).toUpperCase();
c=str.charAt(0);
if(c=='Y'||c=='N') {
break;
}else {
System.out.print("选择错误,请重新输入:");
}
}
return c;
}
private static String readKeyBoard(int limit,boolean blankReturn) {
String line="";
while(scanner.hasNextLine()) {
line=scanner.nextLine();
if(line.length()==0) {
if(blankReturn)return line;
else continue;
}
if(line.length()<1||line.length()>limit) {
System.out.print("输入长度(不大于"+limit+")错误,请重新输入:");
continue;
}
break;
}
return line;
}
}
Data类:
属性都设置为常量,将公司员工,以及设备进行一个统计处理。
public class Data {
public static final int EMPLOYEE=10;//普通员工
public static final int PROGRAMMER=11;//程序员
public static final int DESIGNER=12;//设计师
public static final int ARCHITECT=13;//架构师
public static final int PC=21;//PC
public static final int NOTEBOOK=22;//笔记本
public static final int PRINTER=23;//打印机
public static final String[][] EMPLOYEES= {
{"10","1","马云","22","3000"},
{"13","2","马化腾","32","18000","15000","2000"},
{"11","3","李彦宏","23","7000"},
{"11","4","刘强东","24","7300"},
{"12","5","雷军","28","10000","5000"},
{"10","6","任志强","22","6800"},
{"12","7","柳传志","29","10800","5200"},
{"13","8","杨元庆","30","19800","15000","2500"},
{"12","9","史玉柱","26","9800","5500"},
{"11","10","丁磊","21","6600"},
{"11","11","张朝阳","25","7100"},
{"12","12","杨致远","22","9600","4800"},
};
public static final String[][] EQUIPMENTS= {
{},
{"22","联想T4","6000"},
{"21","戴尔","NEC17寸"},
{"21","戴尔","三星17寸"},
{"23","佳能 2900","激光"},
{"21","华硕","三星17寸"},
{"21","华硕","三星17寸"},
{"23","爱普生20K","针式"},
{"22","惠普m6","5800"},
{"21","戴尔","NFC 17寸"},
{"21","华硕","三星17寸"},
{"21","惠普m6","5800"},
};
}
设备类 Equipment代码块
通过重写接口的抽象方法,使得每个具体的设备类显示不同数据。
public interface Equipment {
public abstract String getDescription();
}
class NoteBook implements Equipment {
private String model;//机器型号
private double price;//价格
public NoteBook() {
super();
}
public NoteBook(String model, double price) {
super();
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;
}
public String getDescription() {
return model + "("+price+")";
}
}
class PC implements Equipment{
private String model;//机器型号
private String display;//显示器名称
public PC() {
super();
}
public PC(String model,String display) {
super();
this.model=model; //机器型号
this.display=display;//显示器名称
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getDisplay() {
return display;
}
public void setDisplay(String display) {
this.display = display;
}
public String getDescription() {
return model + "("+display+")";
}
}
class Printer implements Equipment {
private String name;//机器型号
private String type;//机器类型
public Printer() {
super();
}
public Printer(String name, String type) {
super();
this.name = name;//机器型号
this.type = type;//机器类型
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDescription() {
return name +"("+type+")";
}
}
员工类 Employee代码块
注意:需要重写toString方法,返回相应的数据。可以在超类里写一个getDetails()方法来满足后续子类需要调用基本数据的需求。对所有属性需要进行封装,再有set(),get()方法来赋值或者调用。具体在员工类当中有Programmer、Designer、Architect
//超类员工类
public class Employee {
private int id;
private String name;
private int age;
private double salary;
public Employee() {
super();
}
public Employee(int id, String name, int age, double salary) {
super();
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getDetails() {
return id+"\t"+name+"\t"+age+"\t"+salary;
}
@Override
public String toString() {
return getDetails();
}
}
//父类,程序员类
class Programmer extends Employee {
private int memberId;//开发团队ID
private Status status=Status.FREE;//所有人员的初始状态都是FREE
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;
}
@Override
public String toString() {
return getDetails()+"\t程序员\t"+status+"\t\t\t"+equipment.getDescription();
}
public String getdetDetailsForTeam(){
return memberId+"/"+getId()+"\t"+getName()+"\t"+getAge()+"\t"+getSalary()+"\t程序员";
}
}
//子类:设计师类(继承程序员)
class Designer extends Programmer{
private double bonus;//奖金
public Designer() {
super();
}
public Designer(int id, String name, int age, double salary, Equipment equipment, double bonus) {
super(id, name, age, salary, equipment);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
@Override
public String toString() {
return getDetails()+"\t设计师\t"+getStatus()+"\t"+bonus+"\t\t"+getEquipment().getDescription();
}
public String getdetDetailsForTeam(){
return getMemberId()+"/"+getId()+"\t"+getName()+"\t"+getAge()+"\t"+getSalary()+"\t设计师\t"+getBonus();
}
}
//子类:架构师类(继承设计师)
class Architect extends Designer{
private int stock;
public Architect() {
super();
}
public Architect(int id, String name, int age, double salary, Equipment equipment, double bonus, int stock) {
super(id, name, age, salary, equipment, bonus);
this.stock = stock;
}
public int getStock() {
return stock;
}
public void setStock(int stock) {
this.stock = stock;
}
@Override
public String toString() {
return getDetails()+"\t架构师\t"+getStatus()+"\t"+getBonus()+"\t"+stock+"\t"+getEquipment().getDescription();
}
public String getdetDetailsForTeam(){
return getMemberId()+"/"+getId()+"\t"+getName()+"\t"+getAge()+"\t"+getSalary()+"\t架构师\t"+getBonus()+"\t"+getStock();
}
}
Status代码块
用来表示员工的状态
分为FREE\BUSY\VOCATION三种状态,主要利用枚举的知识点
重写toString()方法来获得NAME
/*
* 表示员工的状态
*/
public class Status {
private final String NAME;
private Status(String name) {
this.NAME=name;
}
//枚举
public static final Status FREE= new Status("FREE");
public static final Status BUSY= new Status("BUSY");
public static final Status VOCATION= new Status("VOCATION");
public String getNAME() {
return NAME;
}
@Override
public String toString() {
return NAME;
}
}
NameListService代码块
负责将Data中的数据封装到Employee[]数组中,同时提供相关操作Employee[]方法。
1.根据项目提供的Data类构建相应大小的employees数组
2.再根据Data类中的数据构建不同的对象,包括Employee、Programmer、Designer和Architect对象、以及相关联的Equipment子类的对象
3.将对象存于数组中
/*
* 负责将Data中的数据封装到Employee[]数组中,同时提供相关操作Employee[]方法。
*/
import static item_3_sgg.Data.*;
public class NameListService {
private Employee[] employees;
/*
* 给employee及数组元素进行初始化
*/
public NameListService() {
// 1.根据项目提供的Data类构建相应大小的employees数组
// 2.再根据Data类中的数据构建不同的对象,包括Employee、Programmer、Designer和Architect对象、以及相关联的Equipment子类的对象
// 3.将对象存于数组中
employees =new Employee[EMPLOYEES.length];//EMPLOYEES.length已经由Data提供
for(int i=0;i<employees.length;i++) {
//获取员工的类型
int type = Integer.parseInt(EMPLOYEES[i][0]);
//获取Employee的4个基本信息
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:
equipment= createEquipment(i);
employees[i]=new Programmer(id,name,age,salary,equipment);
break;
case DESIGNER:
equipment=createEquipment(i);
bonus=Double.parseDouble(EMPLOYEES[i][5]);
employees[i]=new Designer(id,name,age,salary,equipment,bonus);
break;
case ARCHITECT:
equipment=createEquipment(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;
}
}
}
//获取指定index上的员工的设备
private Equipment createEquipment(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://22
String model =EQUIPMENTS[index][1];
double price =Double.parseDouble(EQUIPMENTS[index][2]);
return new NoteBook(model,price);
case PRINTER://23
return new Printer(EQUIPMENTS[index][1],EQUIPMENTS[index][2]);
}
return null;
}
//获取当前所有员工
public Employee[] getALLemployees() {
return employees;
}
public Employee getEmployee(int id) throws TeamException {
for(int i=0;i<employees.length;i++) {
if(employees[i].getId()==id) {
return employees[i];
}
}
throw new TeamException ("找不到指定的员工");
}
}
TeamService代码块
关于开发团队成员的管理:添加、删除等。
1.添加方法public void addMember(Employee e) throws TeamException {}
如果成员已满,不是开发人员,已在本开发团队或者状态不是FREE就都不能进行添加,所以此时都需要抛出异常。
2.删除方法public void removeMember(int memberId) throws TeamException {}
找不到指定的memberId的员工就无法删除,需要抛出异常。
需要将被删除的成员状态改为FREE,后面的元素覆盖前一个元素,实现删除。
//关于开发团队成员的管理:添加、删除等。
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;//记录开发团队中实际的人数
public TeamService() {
super();
}
//得到开发团队成员
public Programmer[] getTeam() {
Programmer[] team=new Programmer[total];
for(int i=0;i<team.length;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("该成员不是开发人员,无法添加");
}
if(isExist(e)) {
throw new TeamException("该成员已在本开发团队中");
}
Programmer p =(Programmer)e;
// if(p.getStatus().getNAME().equals("BUSY"))
if("BUSY".equals(p.getStatus().getNAME())){
throw new TeamException("该成员已是某团队成员");
}else if("VOCATION".equals(p.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] instanceof Programmer) {
numOfPro++;
}
}
if(p instanceof Architect) {
if(numOfArch >=1) {
throw new TeamException("团队中至多只能由一名架构师");
}
}else if(p instanceof Designer) {
if(numOfDes>=2) {
throw new TeamException("团队中至多只能有两名设计师");
}
}else if(p instanceof Programmer) {
if(numOfPro>=3)
throw new TeamException("团队中至多有三名程序员");
}
p.setStatus(Status.BUSY);
p.setMemberId(counter++);
team[total++]=p;
}
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;j<total-1;j++) {
team[j]=team[j+1];
}
team[--total]=null;
}
}
TeamException代码块
用户自定义的异常类,编译时有问题就抛出异常。
public class TeamException extends Exception{
static final long serialVersionUID = -33875124229948L;
public TeamException() {
super();
}
public TeamException(String msg) {
super(msg);
}
}
TeamView代码块
主要模块,用户操作和交互都在这里进行实现
public class TeamView {
private NameListService listSvc =new NameListService();//负责将Data中的数据封装到Employee[]数组中,同时提供相关操作Employee[]方法。
private TeamService teamSvc = new TeamService();//关于开发团队成员的管理:添加、删除等。
private Programmer[] team;
public void enterMainMenu() {
boolean loopFlag=true;
char menu=0;
while(loopFlag) {
if(menu !='1') {
listAllEmployees();
}
System.out.print("1-团队列表 2-添加团队成员 3-删除团队成员 4-退出 请选择(1-4):");
menu=TSUtility.readMenuSelection();
switch(menu) {
case '1':
getTeam();
break;
case '2':
addMember();
break;
case '3':
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=listSvc.getALLemployees();
if(employees==null||employees.length==0) {
System.out.println("公司没有任何员工信息");
}else{
System.out.println("ID\t姓名\t年龄\t工资\t职位\t状态\t奖金\t股票\t领用设备");
for(int i=0;i<employees.length;i++) {
System.out.println(employees[i]);
}
}
System.out.println("---------------------------------------------------------------------------------------------");
}
private void getTeam() {
System.out.print("-------------------------团队成员列表-------------------------\n");
Programmer[] team = teamSvc.getTeam();
if(team==null||team.length==0)
{
System.out.println("开发团队目前没有成员!");
}else{
System.out.println("TID/ID\t姓名\t年龄\t工资\t职位\t奖金\t股票\n");
for(int i=0;i<team.length;i++)
{
System.out.println(team[i].getdetDetailsForTeam());
}
}
}
private void addMember() {
System.out.print("-------------------------添加团队成员-------------------------\n");
System.out.print("请输入要添加的员工ID:");
int id=TSUtility.readInt();
try {
Employee emp=listSvc.getEmployee(id);
teamSvc.addMember(emp);
System.out.println("添加成功");
}catch(TeamException e) {
System.out.println("添加失败,原因:"+e.getMessage());
}
TSUtility.readReturn();
}
private void deleteMember() {
System.out.print("-------------------------删除团队成员-------------------------\n");
System.out.print("请输入要删除的员工TID:");
int memberId=TSUtility.readInt();
System.out.print("确认是否要删除(Y/N):");
char isDelete =TSUtility.readConfirmSelection();
if(isDelete=='N') {
return;
}
try {
teamSvc.removeMember(memberId);
System.out.println("删除成功");
}catch(TeamException e) {
System.out.println("删除失败,原因:"+e.getMessage());
}
TSUtility.readReturn();
}
public static void main(String[] args) {
TeamView view =new TeamView();
view.enterMainMenu();
}
}
总结
完成这个项目耗费时间较长,但涵盖了之前所学Java面向对象的所有知识点,让我加固了面向对象的知识点。
设计此类系统的思路呈现:
1.工具类(TSUtility、Data)的设计
1)考虑所需功能有几个,读取键盘上功能的序列号,然后返回这个序列号
2)确认是否要进行操作,通过‘Y’&&‘N’(用toUpperCase()方法可以转化成大写)
3)根据用户输入,读取键盘上的数字
从键盘输入方法:
private static String readKeyBoard(int limit,boolean blankReturn) {
String line="";
while(scanner.hasNextLine()) {
line=scanner.nextLine();
if(line.length()==0) {
if(blankReturn)return line;
else continue;
}
if(line.length()<1||line.length()>limit) {
System.out.print("输入长度(不大于"+limit+")错误,请重新输入:");
continue;
}
break;
}
return line;
}
2.考虑人员共有属性为父类,然后根据具体情况,可以写新的子类创建特性。
3.将已知信息或者输入的Data存放到人员类的数组里面,并且考虑操作这个数组。
4.考虑实现具体功能的方法(增加,删除,查找,修改)。
5.考虑界面实现以及用户交互。