学生设备管理系统:
每个学校都有很多班级,每个班级都有很多设备。(设备可以更新)
每个设备都有购买价格,每种设备都有折旧率(如每年折旧10%)
- 按班级进行统计,指定的班级有多少的设数量?
- 按班级进行统计,当前时间,指定班级的设备价格总和?(考虑折旧)
- 统计学校所有设备总数,所有设备价格总和?
那么接下来就是分步完成:
-
学校类设计
首先是ClassRoom类:在第一步里面我们暂时只需要用到roomNumber这个属性。
我们默认的是教室编号只读,不能修改,所以封装的时候不需要set方法。
代码如下:
1 public class ClassRoom { 2 private String roomNumber; 3 4 public ClassRoom(String roomNumber) { 5 /** 6 * 这里可以看到,在构造函数里面给roomNumber赋值之后,没有set方法,就无法修改了。 7 * 这就是只读属性。 8 */ 9 this.roomNumber = roomNumber; 10 } 11 12 public String getRoomNumber() { 13 return roomNumber; 14 } 15 }
然后是School类,我们暂时有name和classRooms两个属性。其中对于classRooms的类型选择,我们有进一步的改进。
同时在School类构造函数里面对classRooms的实例化,也是符合思维习惯的一种方式。
1 public class School { 2 private String name; //name是只读的属性,只保留get方法。 3 private List<ClassRoom> classRooms; //表示学校下面的一群班级。 4 5 public School(String name){ 6 /** 7 * 构造函数的作用一般都是初始化 8 */ 9 this.name = name; 10 classRooms = new ArrayList<ClassRoom>(100); 11 } 12 13 public String getName() { 14 return name; 15 } 16 17 // public void setName(String name) { 18 // this.name = name; 19 // } 20 21 /** 22 * 这里的ClassRooms的set方法是不合理的,这样就失去了变化性。 23 * 所以删除set方法,增加添加和删除的两个方法。 24 * @return 25 */ 26 public List<ClassRoom> getClassRooms() { 27 return classRooms; 28 } 29 public void addRoom(ClassRoom classRoom){ 30 this.classRooms.add(classRoom); 31 } 32 33 public void removeRoom(String roomNumber){ 34 for (ClassRoom rm: classRooms) { 35 if(rm.getRoomNumber().equals(roomNumber)){ 36 classRooms.remove(rm); 37 break; 38 } 39 } 40 } 41 }
代码里面的注释还是比较详细的。但是这里的问题就是,如果ClassRooms的数量比较大的时候,removeRoom使用for循环查找的方式就很慢了。所以可以改进一下,对ClassRooms使用Map的数据结构。下面是改进之后的:
1 package edu.nuist.dev.biz; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 public class SchoolPro { 7 private String name; //name是只读的属性,只保留get方法。 8 private Map<String, ClassRoom> classRooms;//存储了教室和主键,优化查找速度。 9 10 public SchoolPro(String name) { 11 this.name = name; 12 classRooms = new HashMap<String, ClassRoom>(100); 13 } 14 15 public String getName() { 16 return name; 17 } 18 19 public Map<String, ClassRoom> getClassRooms() { 20 return classRooms; 21 } 22 23 public void addRoom(ClassRoom classRoom) { 24 this.classRooms.put(classRoom.getRoomNumber(), classRoom); 25 } 26 27 public void removeRoom(String roomNumber) { 28 this.classRooms.remove(roomNumber); 29 } 30 }
可以看到,改进之后,remove只需要一行代码就可以解决了,这里也说明了集合的重要性,对不同的情况作最合适的选择。
最后,我们在ui包内新建一个SchoolTest的类来测试一下,阶段性的测试,可以防止最后各种问题的堆砌,同时可以清理一遍思路,是必须掌握的一个手段。
1 public class SchoolTest { 2 public static void main(String[] args) { 3 SchoolPro school = new SchoolPro("南京信息工程大学"); 4 ClassRoom room1 = new ClassRoom("101"); 5 ClassRoom room2 = new ClassRoom("102"); 6 ClassRoom room3 = new ClassRoom("103"); 7 ClassRoom room4 = new ClassRoom("104"); 8 ClassRoom room5 = new ClassRoom("105"); 9 school.addRoom(room1); 10 school.addRoom(room2); 11 school.addRoom(room3); 12 school.addRoom(room4); 13 school.addRoom(room5); 14 Map<String, ClassRoom> classRoomMap = school.getClassRooms(); 15 Set<String> keySet = classRoomMap.keySet(); 16 //根据主键来循环 17 for (String key : keySet) { 18 System.out.println(key); 19 } 20 21 //移除操作 22 System.out.println("移除103-------------"); 23 classRoomMap.remove("103"); 24 Map<String, ClassRoom> classRoomMap2 = school.getClassRooms(); 25 Set<String> keySet2 = classRoomMap2.keySet(); 26 for (String key : keySet2) { 27 System.out.println(key); 28 } 29 } 30 }
-
设备类设计
要求的是每个教室有多个设备,所以我们首先定义一个Device的abstract类,写上通用的属性方法
1 public abstract class Device { 2 private String deviceNo; //设备编号 3 private double buyPrice; //购买价格 4 private double nowPrice; //当前价格 5 private double oldRate; //折旧率 6 private String deviceType; //设备类型 7 8 public Device(String deviceNo,String deviceType){ 9 this.deviceNo = deviceNo; 10 this.deviceType = deviceType; 11 } 12 13 public String getDeviceNo() { 14 return deviceNo; 15 } 16 17 public double getBuyPrice() { 18 return buyPrice; 19 } 20 21 public void setBuyPrice(double buyPrice) { 22 this.buyPrice = buyPrice; 23 } 24 25 public double getNowPrice() { 26 return nowPrice; 27 } 28 29 public void setNowPrice(double nowPrice) { 30 this.nowPrice = nowPrice; 31 } 32 33 public double getOldRate() { 34 return oldRate; 35 } 36 37 public void setOldRate(double oldRate) { 38 this.oldRate = oldRate; 39 } 40 }
这里要注意的是,我们有一个设备类型,是通过新建一个DeviceType类,在其中定义常量的方法来实现的,根据之后功能的不同,也可以通过接口实现。
在构造方法中加入DeviceType,子类继承实现构造方法时,相当于告诉你,我是Computer,或者是Table。
我们这里假设教室里面的设备有3中,Computer,Table,Chair
1 //Computer类 2 package edu.nuist.dev.biz; 3 public class Computer extends Device{ 4 5 public Computer(String deviceNo) { 6 super(deviceNo,DeviceType.COMPUTER); 7 } 8 } 9 //Chair类 10 package edu.nuist.dev.biz; 11 public class Chair extends Device{ 12 13 public Chair(String deviceNo) { 14 super(deviceNo,DeviceType.CHAIR); 15 } 16 } 17 //Table类 18 package edu.nuist.dev.biz; 19 public class Table extends Device{ 20 21 public Table(String deviceNo) { 22 super(deviceNo,DeviceType.TABLE); 23 } 24 }
同样的,在classRoom类中,我们要管理多个设备,类似于一个学校的多个教室一样,用Map结构来定义。并添加add和remove方法。和之前的类似,不再重复给出代码。
到这里,我们的第二步就完成了
-
统计教室的设备信息
添加一个DeviceTest类来统计
1 public class DeviceTest { 2 public static void main(String[] args){ 3 //新建设备,电脑、桌子、椅子各5个。 4 Computer computer1 = new Computer("C001"); 5 Computer computer2 = new Computer("C002"); 6 Computer computer3 = new Computer("C003"); 7 Computer computer4 = new Computer("C004"); 8 Computer computer5 = new Computer("C005"); 9 Table table1 = new Table("t001"); 10 Table table2 = new Table("t002"); 11 Table table3 = new Table("t003"); 12 Table table4 = new Table("t004"); 13 Table table5 = new Table("t005"); 14 Chair chair1 = new Chair("ch001"); 15 Chair chair2 = new Chair("ch002"); 16 Chair chair3 = new Chair("ch003"); 17 Chair chair4 = new Chair("ch004"); 18 Chair chair5 = new Chair("ch005"); 19 //新建两个教室 20 ClassRoom classRoom1 = new ClassRoom("101"); 21 ClassRoom classRoom2 = new ClassRoom("202"); 22 23 //给教室101添加设备 24 classRoom1.addDevice(computer1); 25 classRoom1.addDevice(computer2); 26 classRoom1.addDevice(computer3); 27 classRoom1.addDevice(table1); 28 classRoom1.addDevice(table2); 29 classRoom1.addDevice(chair1); 30 classRoom1.addDevice(chair2); 31 classRoom1.addDevice(chair3); 32 //给教室202添加设备,添加重复的设备 33 classRoom2.addDevice(computer1); 34 classRoom2.addDevice(computer4); 35 classRoom2.addDevice(computer5); 36 classRoom2.addDevice(table3); 37 classRoom2.addDevice(table4); 38 classRoom2.addDevice(table5); 39 classRoom2.addDevice(table3); 40 classRoom2.addDevice(chair2); 41 classRoom2.addDevice(chair4); 42 classRoom2.addDevice(chair5); 43 44 //获取设备信息 45 Map<String,Device> allDevice1 = classRoom1.getDevices(); 46 System.out.println(classRoom1.getRoomNumber() + "共有设备:" + allDevice1.size()); 47 //列出设备 48 Set<String> keys1 = allDevice1.keySet(); 49 for (String key:keys1){ 50 Device dev = allDevice1.get(key); 51 System.out.println(dev.getDeviceType() + "---" +dev.getDeviceNo()); 52 } 53 54 Map<String,Device> allDevice2 = classRoom2.getDevices(); 55 System.out.println(classRoom2.getRoomNumber() + "共有设备:" + allDevice2.size()); 56 Set<String> keys2 = allDevice2.keySet(); 57 for (String key:keys2){ 58 Device dev = allDevice2.get(key); 59 System.out.println(dev.getDeviceType() + "---" +dev.getDeviceNo()); 60 } 61 } 62 }
这里有注意点:一台设备只能被分配到一个教室,所以我们设置了一个isUsed来判断它在添加时的状态。测试之后发现判断重复是可以的。到此我们解决了第一个问题。
1 public void addDevice(Device device){ 2 //表示Device不为空,并且isUsed为false,才可以添加。 3 if ( device != null){ 4 if (!device.isUsed()){ 5 devices.put(device.getDeviceNo(),device); 6 device.setUsed(true);//改变状态 7 }else { 8 System.out.println(device.getDeviceNo() + "已经被分配了,无法使用"); 9 } 10 }else { 11 System.out.println("设备不存在"); 12 } 13 }
-
统计设备折旧后的价格
首先我们要知道折旧后的价格:
nowPrice = buyPrice - buyPrice * dayOldRate * days
dayOldRate = oldRate / 365
days = nowDate - buyDate
然后在Device类中对getNowPrice修改
1 public double getNowPrice() { 2 double dayOldRate = this.oldRate / 365; 3 long pastTime = new Date().getTime() - this.buyDate.getTime(); 4 long days = pastTime / (3600 * 1000 * 24); 5 this.nowPrice = this.buyPrice - this.buyPrice * dayOldRate * days; 6 return nowPrice; 7 }
然后我们设计一个RateTest类来测试,期间采用的方法是先写第一个,然后设置断点去调试看看nowPrice是否正确,在正确之后再补写其他的,这样就减少了不必要的错误检查。
1 public class RateTest { 2 public static void main(String[] args){ 3 try { 4 SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd"); 5 //新建设备,电脑、桌子、椅子各5个。 6 Computer computer1 = new Computer("C001"); 7 computer1.setOldRate(0.1); 8 computer1.setBuyDate(sd.parse("2015-03-12")); 9 computer1.setBuyPrice(3800); 10 //double a = computer1.getNowPrice(); 设置断点处来查看nowPrice是否计算正确。 11 Computer computer2 = new Computer("C001"); 12 computer2.setOldRate(0.1); 13 computer2.setBuyDate(sd.parse("2016-07-08")); 14 computer2.setBuyPrice(3800); 15 Table table1 = new Table("t001"); 16 table1.setOldRate(0.125); 17 table1.setBuyDate(sd.parse("2013-08-10")); 18 table1.setBuyPrice(280); 19 Chair chair1 = new Chair("ch001"); 20 chair1.setBuyDate(sd.parse("2015-10-01")); 21 chair1.setBuyPrice(300); 22 chair1.setOldRate(0.2); 23 24 ClassRoom classRoom1 = new ClassRoom("101"); 25 classRoom1.addDevice(computer1); 26 classRoom1.addDevice(computer2); 27 classRoom1.addDevice(table1); 28 classRoom1.addDevice(chair1); 29 30 Map<String,Device> allDevice = classRoom1.getDevices(); 31 Set<String> keys = allDevice.keySet(); 32 System.out.println(classRoom1.getRoomNumber() + "共有设备:" + allDevice.size()); 33 double allPrice = 0; 34 for (String key:keys){ 35 Device dev = allDevice.get(key); 36 double nowPrice = dev.getNowPrice(); 37 allPrice += nowPrice; 38 System.out.println(dev.getDeviceNo() + "---" + dev.getDeviceType() + "---" +dev.getNowPrice()); 39 } 40 System.out.println(classRoom1.getRoomNumber() + "当前教室的设备总价格:" + allPrice); 41 42 }catch (Exception e){ 43 e.printStackTrace(); 44 } 45 } 46 }
-
重写计算设备的价格
我们考虑到实际的情况,电脑的折旧率根据实际情况,波动很大,所以我们需要在Computer类中增加一个权值。利用重写来实现多态。
1 public class Computer extends Device{ 2 private double value; //价格计算的加权值 3 4 public Computer(String deviceNo) { 5 super(deviceNo,DeviceType.COMPUTER); 6 this.value = 1; 7 } 8 9 public double getNowPrice(){ 10 this.nowPrice = super.getNowPrice() * value; 11 return this.nowPrice; 12 } 13 14 public double getValue() { 15 return value; 16 } 17 18 public void setValue(double value) { 19 this.value = value; 20 } 21 }
加上权值之后,价格的变化就更符合实际情况。
至此,我们就完成了问题二。
-
统计学校设备总价
我们的过程就是:学校->班级->设备->价格。依次寻找。
添加测试类
1 package edu.nuist.dev.ui; 2 3 import edu.nuist.dev.biz.*; 4 5 import java.text.SimpleDateFormat; 6 import java.util.Map; 7 import java.util.Set; 8 9 public class AllDeviceTest { 10 public static void main(String[] args){ 11 try { 12 SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd"); 13 Computer computer1 = new Computer("C001"); 14 computer1.setOldRate(0.1); 15 computer1.setBuyDate(sd.parse("2015-03-12")); 16 computer1.setBuyPrice(3800); 17 computer1.setValue(1.15); 18 Computer computer2 = new Computer("C002"); 19 computer2.setOldRate(0.1); 20 computer2.setBuyDate(sd.parse("2016-07-08")); 21 computer2.setBuyPrice(3800); 22 computer2.setValue(1.4); 23 Table table1 = new Table("t001"); 24 table1.setOldRate(0.125); 25 table1.setBuyDate(sd.parse("2013-08-10")); 26 table1.setBuyPrice(280); 27 Chair chair1 = new Chair("ch001"); 28 chair1.setBuyDate(sd.parse("2015-10-01")); 29 chair1.setBuyPrice(300); 30 chair1.setOldRate(0.2); 31 32 ClassRoom classRoom1 = new ClassRoom("101"); 33 classRoom1.addDevice(computer1); 34 classRoom1.addDevice(computer2); 35 classRoom1.addDevice(table1); 36 classRoom1.addDevice(chair1); 37 38 ClassRoom classRoom2 = new ClassRoom("202"); 39 Computer computer3 = new Computer("C003"); 40 computer3.setOldRate(0.1); 41 computer3.setBuyDate(sd.parse("2016-11-29")); 42 computer3.setBuyPrice(3900); 43 computer3.setValue(1.2); 44 classRoom2.addDevice(computer3); 45 46 SchoolPro school = new SchoolPro("南京信息工程大学"); 47 school.addRoom(classRoom1); 48 school.addRoom(classRoom2); 49 50 Map<String,ClassRoom> allRooms = school.getClassRooms(); 51 Set<String> roomKeys = allRooms.keySet(); 52 int allDeviceCount = 0; 53 double allDevicePrice = 0; 54 for (String key:roomKeys){ 55 ClassRoom classRoom = allRooms.get(key); 56 Map<String,Device> allDevice = classRoom.getDevices(); 57 allDeviceCount += allDevice.size(); 58 Set<String> devKeys = allDevice.keySet(); 59 for (String dev:devKeys){ 60 Device device = allDevice.get(dev); 61 allDevicePrice += device.getNowPrice(); 62 } 63 } 64 System.out.println(school.getName() + "所有设备总数:" + allDeviceCount); 65 System.out.println(school.getName() + "所有设备总价格:" + allDevicePrice); 66 67 }catch (Exception e){ 68 e.printStackTrace(); 69 } 70 } 71 }
通过一个简单的例子,我们大致了解了学校的设备的个数和总价格。
到此,我们解决了问题三。
https://pan.baidu.com/s/1pNr8hlx
查看可执行源码。
总结
简单的OO练习,涵盖了继承多态的主要思想,结合实际的例子,加深了对面向对象的理解。同时,一些代码的规范,技巧,也是值得反复揣摩学习的。
Alkane 2018-01-21 23:35:23