快递管理程序怎么写?(面向对象+MVC+IO+集合)帮你一步搞定

快递管理控制台项目

任务描述:

为了熟悉快递管理业务,完成快递管理控制台项目,具体需求如图:
在这里插入图片描述
我们将数据存储在集合中,但是在程序被关闭后,存储的数据也就丢失了。那我们就需要用到 IO,使用 IO 技术将快递数据存储到文件中了。文件存储快递信息后,可以在每次启动应用时便读取到文件中的内容,从而实现程序数据的一直存在。 现在我们来开始完成这项项目吧

任务过程

  1. 明确具体需求
  2. 选择合适的集合存储快递数据
  3. 将快递数据存储到文件中
  4. 程序启动自动加载文件中数据
  5. 多次测试保证功能齐全,无Bug出现

涉及知识点

1.面向对象
2.类集(集合)
3.IO(文件输入输出)
4.MVC模型

厘清思路

第一步:

先了解快递信息有哪些,我们根据任务描述得知快递信息应该有:
1.快递单号
2.快递公司
3.取件码
4.存储快递位置
根据这些信息,我们来创建一个Express类,用来封装这些信息含有的属性。

代码如下:

在这里插入代码片
public class Express implements Serializable {
    
    
 private String id; // 快递单号
 private String company;// 快递公司
 private int code;// 取件码

// 构造方法
 public Express() {
    
    
  super();
 }
 public Express(String id, String company, int code) {
    
    
  super();
  this.id = id;
  this.company = company;
  this.code = code;
 }

//Setter、Getter
 public String getId() {
    
    
  return id;
 }
 public void setId(String id) {
    
    
  this.id = id;
 }
 public String getCompany() {
    
    
  return company;
 }
 public void setCompany(String company) {
    
    
  this.company = company;
 }
 public int getCode() {
    
    
  return code;
 }
 public void setCode(int code) {
    
    
  this.code = code;
 }

//equals、hashCode
 @Override
 public int hashCode() {
    
    
  final int prime = 31;
  int result = 1;
  result = prime * result + code;
  result = prime * result + ((company == null) ? 0 : company.hashCode());
  result = prime * result + ((id == null) ? 0 : id.hashCode());
  return result;
 }
 @Override
 public boolean equals(Object obj) {
    
    
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  Express other = (Express) obj;
  if (code != other.code)
   return false;
  if (company == null) {
    
    
   if (other.company != null)
    return false;
  } else if (!company.equals(other.company))
   return false;
  if (id == null) {
    
    
   if (other.id != null)
    return false;
  } else if (!id.equals(other.id))
   return false;
  return true;
 }

//toString
 @Override
 public String toString() {
    
    
  return "快递单号:" + id + ", 快递公司:" + company + ", 取件码:" + code ;
 }

}

怎么样,这里面有接口,有equals和hashCode方法,可能现在我们还看不出它们有什么用处,因为这是我最终写的Express类,它们的用处肯定是有的,我们只有在一步步做的时候才能去会发现它们。好了,接下来我们再看下一步。

第二步:

通过上一步,我们封装了快递信息从而创建出了一个Express类,以后我们无论是添加、删除、修改、查询,直接用Express创建对象,岂不很方便,对吧。现在我们来简单了解一下MVC模型。
M:表示数据的存取
V:表示视图效果
C:表示调用逻辑

我们就这么理解,我们要给用户展示的东西,就是这个V视图效果,我们可以把需要展示的方法功能封装成一个类,里面有我们想要给用户展示看的菜单界面,主页页面,登录界面,操作界面,显示信息界面等等一系列的视图界面或提示用户的方法功能,我们把它封装成一个类。我现在把它封装成了一个View类。到时我们需要用到这些功能方法的话,就直接创建一个View对象,这样的话,代码就可以显得不杂乱。这也是培养我们面向对象的思维能力,我们要慢慢摆脱我们面向过程的思维。从执行者变成一个指挥者吧。

那么M呢,Model 模型,它表示数据信息的存取,我们需要进行添加,删除,修改,查看时,都需要有一个数据信息的存取过程。为了方便,我们同样可以把这些功能方法封装成一个类,到时要用这些功能方法时,我们直接用对象调用就行了。我在这里把它封装成了一个ExpressDao类。

那么C呢,Controller 控制器,程序的入口,负责响应用户操作 并调用相对应的业务逻辑模块 完成整个功能需求。

现在我们对MVC应该有了一个具体的认识了吧,它的作用也有很多,比如:使代码更容易维护,有利于代码复用。

现在我提供一个关于视图效果View类的代码:

扫描二维码关注公众号,回复: 11933797 查看本文章
在这里插入代码片
public class View {
    
    
    private Scanner scanner = new Scanner(System.in);
    private Random random = new Random();
    private List<Integer> li = new ArrayList<Integer>();
    
    //开始
    public void start() {
    
    
     System.out.println("欢迎来到快递柜管理系统");
    }
    
    //结束
    public void end() {
    
    
     System.out.println("再见,欢迎下次再来哦...");
    }
    
    //接收用户输入
    public int input() {
    
    
     System.out.println("根据相应的序号,请输入:");
     int num = 0;
     while(true) {
    
    
         try {
    
    
             num = scanner.nextInt();
             return num;
         }catch (Exception e) {
    
    
    System.out.println("你的输入有误,请重新输入:");
       scanner.nextInt();
   }
     }
     
    }
      //打印快递信息
    public void printExpress(Express e) {
    
    
     System.out.println("快递单号:"+e.getId()+",快递公司:"+e.getCompany()+",取件码:"+e.getCode());
    }
    
    //输入信息有误
    public void inputError() {
    
    
     System.out.println("你输入的信息有误......");
    }
    
    //快递柜空了
    public void nullExpress(){
    
    
        System.out.println("不存在此快递");
    }
    
    //随机生成一个取件码
    public int code() {
    
    
     while(true) {
    
    
      int num = 0;
         int code = (int)(random.nextInt(899999)+100000);
      for(int i=0; i<li.size();i++) {
    
    
       if(li.get(i) == code) {
    
    
        num ++;
       }
      }
      if(num == 0) {
    
    
       li.add(code);
       return code;
      }
     }
    }
    
    //登录
    public int login() {
    
    
     System.out.println("请登录: 1.快递员\t  2.普通用户 \t  3.退出   ");
     return input();
    }
    
    //管理员
    public int aindex() {
    
    
     System.out.println("请选择你要进行的操作:1.快递录入\t 2.快递删除\t 3.快递修改\t 4.查看所有快递\t5.返回上一级目录");
     return input();
    }
    
    //用户
    public int uindex() {
    
    
     System.out.println("请选择你要进行的操作:1.取快递\t  2.返回上一级目录");
     return input();
    }
    
    //快递录入
    public Express insert() {
    
    
     System.out.println("请输入你要添加的快递单号:");
     String id = scanner.next();
     System.out.println("请输入你要添加的快递公司:");
     String company = scanner.next();
     int code = code();
     Express e = new Express();
     e.setId(id);
     e.setCompany(company);
     e.setCode(code);
     return e;
    }
    
    //快递已存在
    public void expressError() {
    
    
     System.out.println("此快递已存在...");
    }
    
    //快递录入成功
    public void InsertSuccess() {
    
    
     System.out.println("恭喜你,快递录入成功...");
    }
    
    //快递录入失败
    public void insertError() {
    
    
     System.out.println("很遗憾,快递录入失败...");
    }
    
    //找出要删除的快递
    public String delete() {
    
    
     System.out.println("请输入你要删除的快递单号:");
     String id = scanner.next();
     return id;
    }
    
    //删除确认
    public int deleteConfirm() {
    
    
     System.out.println("确认是否删除: 1.确认\t  2.取消");
     return input();
    }
    
    //快递删除成功
    public void deleteSuccess() {
    
    
     System.out.println("恭喜你,快递删除成功...");
    }
    
    //快递删除失败
    public void deleteError() {
    
    
     System.out.println("很遗憾,快递删除失败...");
    }
    
    //找出要修改的快递单号
    public String update() {
    
    
     System.out.println("请输入你要修改的快递单号:");
     String id = scanner.next();
     return id;
    }
    
    //修改成功
    public void updateSuccess() {
    
    
     System.out.println("恭喜你,快递修改成功...");
    }
    
    //修改失败
    public void updateError() {
    
    
     System.out.println("很遗憾,快递修改失败...");
    }
    
    //查看所有快递
    public void printAll(List<Express> list) {
    
    
     for(Express e : list) {
    
    
      printExpress(e);
     }
    }
    
    //取快递
    public int getExpress() {
    
    
     System.out.println("请输入取件码:");
     int num = 0;
     while(true) {
    
    
         try {
    
    
             num = scanner.nextInt();
             return num;
         }catch (Exception e) {
    
    
    System.out.println("你的输入有误,请重新输入:");
    num = scanner.nextInt();
   }
     }
    }
    
    //取件失败
    public void getError() {
    
    
     System.out.println("很遗憾,取件失败");
    }
    
    //取件成功
    public void getSuccess() {
    
    
     System.out.println("恭喜你,取件成功");
    }
    
    //取件提醒
    public void printGet() {
    
    
     System.out.println("请您尽快取件");
    }    
    
    //删除取件码
    public void deleteCode(int code) {
    
    
     li.remove((Integer)code);
    }
    
    //快递所在位置
    public void address(int index) {
    
    
     System.out.println("快递在"+index+"号快递柜");
    }
    
    
    
}

怎么样,方法看着是不是特多,有点烟花缭乱,为什么要创建那么多方法,甚至只为了输出一句话也要创建一个方法,因为它有利于代码复用啊,有些方法我是要调用多次的,虽然只有一句话,但它能调用到多次,所有为此也是值得的。

第三步:

创建集合,集合有
Set接口的类集
List接口的类集
Map接口的类集
那在这里我选择的是List接口下的ArrayList类集,因为它是我认为比较适合的一个集合,
ArrayList是一个可改变大小的数组.当更多的元素加入到ArrayList中时,其大小将会动态地增长.内部的元素可以直接通过get与set方法进行访问,它是异步处理,效率很高,考虑到我这个不需要同步,我就选择它了。
现在我们知道该选择ArrayList类集,我们也知道创建集合是为了存储快递信息,而这些快递信息都封装在Express类,所以我们创建的ArryaList的类型为Express类。创建格式为:

List<Express> list = new ArrayList<Express>();

那我们在哪个类需要用到集合呢?不用想,就是数据信息的存取那个类,也就是我们ExpressDao这个类中,因为这个专门是用来存信息的,用来取信息的,那肯定都是需要在集合里存啊,在集合里取啊,对吧。但是我们得注意把它声明在成员属性里,顺便进行初始化。因为我们都知道在这个类的很多方法功能都需要用到这个集合。否则我们访问的就不是同一个集合。

第四步

现在我们好集合后,但是我们还没有解决问题,因为我们的需求是在程序被关闭后,我们的存储的数据不能丢失,那我们需要用到IO,使用IO技术将集合里的快递数据存储到文件中,文件存储了之后,那我们下次启动时,再从文件里读取快递信息并存储到集合里,这样我们就保证了我们存储的数据不会丢失了。

我的简单思路就是:
在原有的基础上,创建了两个方法
一个是读取文件快递信息的方法,返回值是Express类型的List集合。

在这里插入代码片
//读取快递文件信息
 public List<Express> fileInput() throws Exception {
    
    
  try {
    
    
  ois = new ObjectInputStream(new FileInputStream(new File("d:/快递.txt")));
     Object o = ois.readObject();
     list1 = (ArrayList<Express>) o;
     ois.close();
     return list1;
     }catch (EOFException e) {
    
    
   System.out.println("没有任何快递信息");
  }
  return null;
 }

另一个是存储文件快递信息的方法,把集合里的快递信息写入到文件中去。

在这里插入代码片
//存储快递文件信息
 public void fileOutput(List<Express> list) throws IOException {
    
    
     oos = new ObjectOutputStream(new FileOutputStream(new File("d:/快递.txt")));
     oos.writeObject(list);
     System.out.println("存储成功...");
     oos.close();
 }

在这里我用到了对象序列化和反序列化,我在这里简单解释一下这两个知识点。
对象序列化:把对象存储到文件中的过程。
反序列化:把之前序列后的文件中数据再变成对象的过程。

但是请注意:
实现序列化先将把需要序列化的类实现Serializable接口,该接口不需要实现序列化的方法,但是它一定要实现。
实现该接口是为了标注对象是可被序列化的。然后我们创建ObjectOutputStream对象,使用FileOutputStream来构造ObjectOutputStream对象,最后我们使用ObjectOutputStream对象的writeObject(Object o)方法就可以将o对象输出,存储到文件中。

现在知道我们那个Express类为什么要实现那个接口了吧。O(∩_∩)O

然后在进入一些插入、修改、删除、取件等操作时,我们同时也进行一个存储文件信息的操作,这样我们的文件信息就和集合里的快递保持一致了。

我的艰辛路程:
其实在一开始的时候,我对于怎么删除,怎么修改文件里的快递信息真的是想了老半天。我知道怎么读取文件快递信息,怎么存储文件快递信息,但是就是不知道怎么修改或删除文件里的快递信息,我转不过弯了,我给自己挖坑,我很复杂化了,还创建了两个集合,一个是存储文件快递信息的集合,一个是运行在程序刚录入快递信息的集合。最后还是弄不好,出现了很多重复的快递信息。最后求教了别人,才点醒了我。

那么文件这些读取,存储的方法放哪呢,和集合一样,都是放在我们数据存取的类里,也是ExpressDao这个类中。
现在我提供Express类中的代码,:

在这里插入代码片
public class ExpressDao {
    
    
private List<Express> list1 = new ArrayList<Express>();
    private ObjectOutputStream oos;
    private ObjectInputStream ois;
 public List<Express> getList1() {
    
    
  return list1;
 }
public void setList1(List<Express> list1) {
    
    
  this.list1 = list1;
 }
//读取快递文件信息
 public List<Express> fileInput() throws Exception {
    
    
  try {
    
    
  ois = new ObjectInputStream(new FileInputStream(new File("d:/快递.txt")));
     Object o = ois.readObject();
     list1 = (ArrayList<Express>) o;
     ois.close();
     return list1;
     }catch (EOFException e) {
    
    
   System.out.println("没有任何快递信息");
  }
  return null;
 }
 //存储快递文件信息
 public void fileOutput(List<Express> list) throws IOException {
    
    
     oos = new ObjectOutputStream(new FileOutputStream(new File("d:/快递.txt")));
     oos.writeObject(list);
     System.out.println("存储成功...");
     oos.close();
 }
//快递信息的存入
 public boolean insert(Express e) {
    
    
  list1.add(e);//添加快递信息
  return true;
 }
 
 //快递信息的删除
 public boolean delete(Express e) {
    
    
  list1.remove(e); //删除刚录入的快递信息
  return true;
 }
 
 //快递信息的修改
 public boolean uadate(Express e1, Express e2) {
    
    
  //修改刚录入的快递信息
  list1.remove(e1);
  list1.add(e2);
  return true;
 }
 
 //查看所有快递信息
 public List<Express> getAll(){
    
    
  return list1;
 }
 
 //查询单个快递(快递单号查询)
 public Express getById(String id) {
    
    
  //在刚录入的快递信息里找
  for(Express e : list1) {
    
    
   if(e.getId().equals(id)) {
    
    
    return e;
   }
  }
        return null;
 }
 
 //取件码查询
 public Express getByCode(int code) {
    
    
  //在刚录入的快递里取
  for(Express e : list1) {
    
    
   if(e.getCode() == code) {
    
    
    return e;
   }
  }
  return null;
 }
 
 //获取快递的位置
 public int getIndex(Express e) {
    
    
  for(Express ee : list1) {
    
    
   if(ee.getId().equals(e.getId())&&ee.getCompany().equals(e.getCompany())&&ee.getCode()==e.getCode()) {
    
    
    return list1.indexOf(ee);
   }
  }
  
  return 0;
 }
 
}

应该是不难理解的,我有注释的。就涉及了一些我前面所学的面向对象,以及一些Java基础语法,再加上这次所学的IO跟集合,把这些知识点融会贯通一下,我们都可以做出这么一个项目。

第五步:

这一步,我们该思考调用逻辑,结合我们创建的类,以及这些类封装的方法功能,还有我们的任务描述来去调用。

首先

我们需要用到我们创建的View类和ExpressDao类,我们肯定是要调用这两个类里的功能方法的,所以在一开始我们把它声明在成员属性里,创建这两个类的对象,进行初始化。
代码如下:

在这里插入代码片
private static ExpressDao dao;
 private static View view;
 
 //对成员属性进行初始化
 public static void init() {
    
    
  dao = new ExpressDao();
  view = new View();
 }

然后我们根据任务描述以及操作过程来思考。

第一步

我们需要选择我们的身份,我们就创建一个选择身份的方法:
代码如下:

在这里插入代码片
//角色身份权限选择
 public static void login() throws Exception  {
    
    
 ha: while(true) {
    
    
  int num = view.login();
  List<Express> li = dao.fileInput();
  dao.setList1(li);  //读取出来放到集合里去
  switch(num) {
    
    
  //选择管理员
  case 1 :
   aindex();
   break;
     //选择用户
  case 2:
   uindex();
   break;
  //退出
  case 3:
   view.end();
   break ha;
  //输入有误
  default:
   System.out.println("输入有误...");
   break ha;
  }
  }
 }

第二步

我们需要想到操作界面,用户有用户的操作界面,管理员有管理员的操作界面
代码如下:

在这里插入代码片
//管理员操作菜单界面
 public static void aindex() throws Exception {
    
    
 ha: while(true) {
    
    
  int num = view.aindex();
     switch(num) {
    
    
     //快递录入
     case 1:
      insert();
      //存储文件快递信息
   dao.fileOutput(dao.getAll());
      break;
     //快递删除
     case 2:
         delete();
         dao.fileOutput(dao.getAll());
         break;
     //快递修改
     case 3:
      update();
      dao.fileOutput(dao.getAll());
      break;
     //查看所有快递
     case 4:
      printAll();
      break;
     //返回上一级目录
     case 5:
      break ha;
     //输入有误
     default:
      System.out.println("输入有误...");
      break ha;
     }
  }
 }
 
 //普通用户操作菜单界面
 public static void uindex() throws IOException {
    
    
 ha: while(true) {
    
    
  int num = view.uindex();
  switch(num) {
    
    
  //取快递
  case 1:
   int code = view.getExpress();
   Express e = dao.getByCode(code);
   if(e!=null) {
    
    
    view.address(dao.getIndex(e));
    view.printExpress(e);
    view.printGet();
    if(dao.delete(e)) {
    
    
     view.deleteCode(e.getCode());
    }
    dao.fileOutput(dao.getAll());
   }else {
    
    
    view.nullExpress();
   }
   break ;
  //返沪上一级目录
  case 2:
   break ha;
  //输入有误
  default:
   System.out.println("输入有误...");
   break ha;
  }
     } 
 }

第三步:

管理员的操作方法具体实现的调用

在这里插入代码片
//录入操作
 public static void insert(){
    
    
  Express e = view.insert();
  //判断插入的单号是否有重复
  if(dao.getById(e.getId())!=null) {
    
    
   //表示快递已经有了
   view.expressError();
  }else {
    
    
   if(dao.insert(e)) {
    
    
    //表示录入成功,顺便显示录入信息
    view.InsertSuccess();
    view.printExpress(e);
   }else {
    
    
    //表示录入失败
    view.insertError();
   }
  }
 }
 
 //删除操作
 public static void delete() {
    
    
  String id = view.delete();
  Express e = dao.getById(id);
  if(e!=null) {
    
    
   int num = view.deleteConfirm();
   switch(num) {
    
    
   //确认删除
   case 1:
    if(dao.delete(e)) {
    
    
     view.deleteSuccess();
     //删除取件码
     view.deleteCode(e.getCode());
    }else {
    
    
     view.deleteError();
    }
    break;
   //取消删除
   case 2:
    System.out.println("OK,你已取消了删除操作");
    break;
      default:
       System.out.println("你的输入有误...");
       break;
   }
   
  }else {
    
    
   //表示没有你要删除的快递
   view.nullExpress();
  }
 }
 
 //修改操作
 public static void update() {
    
    
  String id = view.update();
  Express e = dao.getById(id);
  if(e!=null) {
    
    
   view.printExpress(e);
   Express ee = view.insert();
   if(dao.uadate(e, ee)) {
    
    
    //修改成功
    view.updateSuccess();
    view.deleteCode(e.getCode());
   }else {
    
    
    //修改失败
    view.updateError();;
   }
  }else {
    
    
   //表示没有你要修改的快递
   view.nullExpress();
  }
 }
 
 //查看所有快递
 public static void printAll() throws Exception {
    
    
  List<Express> li = dao.getAll();
  if(li.size()>0) {
    
    
   view.printAll(li);
  }else {
    
    
   System.out.println("快递柜空了...");
  }
 }

第四步:

结合以上我们创建的方法,思考程序运行的步骤过程。

在这里插入代码片
//主界面
 public static void main(String[] args) throws Exception {
    
    
  init();//初始化方法
  view.start();//欢迎用户,提示用户程序已运行
  login();//选择身份就可以进行相关操作。因为这个方法已经调用了相关操作的方法。
  
 }

结语

人生或是学习,就像一场马拉松比赛,不到最后一刻,就不要停下,在Java的赛道上,愿你我都能跑在最前列。

猜你喜欢

转载自blog.csdn.net/aljp123/article/details/108179456