尚硅谷MVC架构项目3总结

视频链接:尚硅谷Java入门视频教程

资料链接:https://wwz.lanzouy.com/ixtFK0eqcfpi

运行截图

image.png

image.png

image.png

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

主要知识点

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

软件设计结构

该软件有三个模块组成

image.png

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

开发步骤

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

在这里插入图片描述

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

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

第二步-实现service包中的类

在这里插入图片描述

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

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

在这里插入图片描述
TeamService类设计
在这里插入图片描述

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

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

image.png

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

Employee类及其子类的设计

image.png

说明:

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

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

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

Data

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

NameListService类的设计

员工列表的业务逻辑
这个就是获得员工,获得指定员工,
image.png

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 方法比较

https://img-blog.csdnimg.cn/20210422164544846.png

equals和==区别

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

image.png

自定义一个异常类

一般自定义异常类就继承
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("该员工不存在");
   }
}

单元测试

https://www.bilibili.com/video/BV1Kb411W75N?p=396&t=11.1

单元测试需要导包

import org.junit.Test;

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

TeamService类的设计

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

image.png

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

  • 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
}

image.png

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

image.png

经典数组[i++]
就是显示完[i]后,然后i++
image.png

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

image.png

尚硅谷Java入门视频教程小问题解答

举个例子就明白了

假如团队中只有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);

TeamView中显示开发团队成员

代码如下:

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中添加开发团队成员

https://www.bilibili.com/video/BV1Kb411W75N?p=404

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中删除开发团队成员

https://www.bilibili.com/video/BV1Kb411W75N?p=405


// 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加入了默认方法和静态方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值