Java诊疗数据导入与Wizyty对象构建及设计问题咨询
问题描述
我正在开发一个程序,需导入Doctor、Patient、Visits三个文本文件,实现患者与医生关联并构建Wizyty对象。当前问题是:导入Visits文件创建Wizyty对象时,会直接读取任意医生ID和患者ID,需添加校验逻辑,确保同一行的医生ID和患者ID真实存在后再构建对象。
现有Java代码如下:
public static void main(String[] args) { List<Lekarz> lekarz = new ArrayList<>(); try { File fileLekarze = new File("src/com/company/lekarze.txt"); Scanner readerLekarze = new Scanner(fileLekarze); readerLekarze.nextLine(); while (readerLekarze.hasNextLine()) { String[] data = readerLekarze.nextLine().trim().split("\t+"); lekarz.add(new Lekarz(Integer.parseInt(data[0]), data[1], data[2], data[3], new SimpleDateFormat("yyyy-MM-dd").parse(data[4]), data[5], data[6])); } readerLekarze.close(); } catch (FileNotFoundException e) { System.out.println("Error File Lekarze"); e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } List<Pacjenci> pacjent = new ArrayList<>(); try { File pacjenciFile = new File("src/com/company/pacjenci.txt"); Scanner readerPacjenci = new Scanner(pacjenciFile); readerPacjenci.nextLine(); while (readerPacjenci.hasNextLine()) { String[] data = readerPacjenci.nextLine().trim().split("\t"); pacjent.add(new Pacjenci(Integer.parseInt(data[0]), data[1], data[2], data[3], new SimpleDateFormat("yyyy-MM-dd").parse(data[4]))); } readerPacjenci.close(); } catch (FileNotFoundException e) { System.out.println("Error File Pacjenci"); e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } List<Wizyty> wizytyList = new ArrayList<>(); try { File fileWizyty = new File("src/com/company/wizyty.txt"); Scanner readerWizyty = new Scanner(fileWizyty); readerWizyty.nextLine(); while (readerWizyty.hasNextLine()) { String[] data = readerWizyty.nextLine().trim().split("\t"); Lekarz lekarz1 = lekarz.stream() .filter(m -> m.getIdLekarza() == Integer.parseInt(data[0])) .findAny() .orElse(null); Pacjenci pacjenci1 = pacjent.stream() .filter(m -> m.getIdPacjenta() == Integer.parseInt(data[1])) .findAny() .orElse(null); Wizyty wizyta = new Wizyty(Integer.parseInt(data[0]), Integer.parseInt(data[1]), new SimpleDateFormat("yyyy-MM-dd").parse(data[2])); wizytyList.add(wizyta); } readerWizyty.close(); } catch (FileNotFoundException e) { System.out.println("Error File Wizyty"); e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } System.out.println(wizytyList); }
文本文件格式
- Visits文件(wizyty.txt):
Id_lekarza Id_pacjenta Data_wizyty 23 124 2006-12-13 23 172 2006-1-25
- Doctor文件(lekarze.txt):
Id_lekarza Nazwisko Imie Specjalnosc Data_urodzenia NIP PESEL 23 Kadaj Monika laryngolog 1965-03-16 879-122-69-94 65031687654
- Patient文件(pacjenci.txt):
Id_pacjenta Nazwisko Imie PESEL Data_urodzenia 100 Kowal Waldemar 01211309876 2001-1-13
疑问点
- 已从Wizyty的构造器中移除了Doctor和Patient对象,此做法是否合理?是否应保留并使用继承?
- 如何修改现有代码,使用真实的Lekarz和Pacjenci对象来构建Wizyty对象?
- 后续需开发统计患者就诊次数、医生接诊量排名等功能,能否给出相关建议?
解答
1. 构造器移除对象的合理性与继承问题
- 只存ID不关联真实对象的做法不合理。后续做统计时,每次都要通过ID去查询对应的医生/患者对象,不仅效率低,代码也会冗余。直接关联真实对象能让Wizyty的语义更清晰:一次就诊是「具体的医生」和「具体的患者」在某天的互动,而非两个ID的无意义组合。
- 不需要使用继承。继承是「is-a」(是一种)关系,Wizyty既不是医生也不是患者,它和两者是「has-a」(拥有)的关联关系,所以应该在Wizyty中持有Lekarz和Pacjenci的引用,而非继承。
2. 修改代码用真实对象构建Wizyty并添加校验
首先调整Wizyty类的构造器,让它接收真实的医生、患者对象和就诊日期:
public class Wizyty { private Lekarz lekarz; private Pacjenci pacjent; private Date dataWizyty; public Wizyty(Lekarz lekarz, Pacjenci pacjent, Date dataWizyty) { this.lekarz = lekarz; this.pacjent = pacjent; this.dataWizyty = dataWizyty; } // 提供getter方法,后续统计功能需要用到 public Lekarz getLekarz() { return lekarz; } public Pacjenci getPacjent() { return pacjent; } public Date getDataWizyty() { return dataWizyty; } }
然后修改主方法中读取Wizyty的逻辑,添加校验(只有医生和患者都存在时才创建对象),同时用Map存储ID与对象的映射提升查找效率:
List<Wizyty> wizytyList = new ArrayList<>(); // 将医生和患者列表转为ID映射的Map,避免每次遍历列表查询 Map<Integer, Lekarz> lekarzMap = lekarz.stream() .collect(Collectors.toMap(Lekarz::getIdLekarza, l -> l)); Map<Integer, Pacjenci> pacjentMap = pacjent.stream() .collect(Collectors.toMap(Pacjenci::getIdPacjenta, p -> p)); try { File fileWizyty = new File("src/com/company/wizyty.txt"); Scanner readerWizyty = new Scanner(fileWizyty); readerWizyty.nextLine(); // 跳过表头 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); while (readerWizyty.hasNextLine()) { String[] data = readerWizyty.nextLine().trim().split("\\s+"); // 用空白分割,兼容多个制表符/空格 int lekarzId = Integer.parseInt(data[0]); int pacjentId = Integer.parseInt(data[1]); Date dataWizyty = sdf.parse(data[2]); // 校验医生和患者是否存在 Lekarz existingLekarz = lekarzMap.get(lekarzId); Pacjenci existingPacjent = pacjentMap.get(pacjentId); if (existingLekarz != null && existingPacjent != null) { wizytyList.add(new Wizyty(existingLekarz, existingPacjent, dataWizyty)); } else { // 打印无效记录日志,跳过错误数据 System.out.printf("无效就诊记录:医生ID %d 或患者ID %d 不存在%n", lekarzId, pacjentId); } } readerWizyty.close(); } catch (FileNotFoundException e) { System.out.println("Error File Wizyty"); e.printStackTrace(); } catch (ParseException e) { System.out.println("日期解析错误"); e.printStackTrace(); }
3. 统计功能开发建议
患者就诊次数统计
用Map存储患者与就诊次数的映射,通过流式API分组统计:
Map<Pacjenci, Long> pacjentWizytyCount = wizytyList.stream() .collect(Collectors.groupingBy(Wizyty::getPacjent, Collectors.counting())); // 打印统计结果 pacjentWizytyCount.forEach((pacjent, count) -> System.out.printf("患者 %s %s 就诊次数:%d%n", pacjent.getImie(), pacjent.getNazwisko(), count));
医生接诊量排名
先分组统计接诊次数,再按次数降序排序:
List<Map.Entry<Lekarz, Long>> lekarzRanking = wizytyList.stream() .collect(Collectors.groupingBy(Wizyty::getLekarz, Collectors.counting())) .entrySet() .stream() .sorted(Map.Entry.<Lekarz, Long>comparingByValue().reversed()) .collect(Collectors.toList()); // 打印排名 System.out.println("医生接诊量排名:"); int rank = 1; for (Map.Entry<Lekarz, Long> entry : lekarzRanking) { Lekarz l = entry.getKey(); System.out.printf("%d. %s %s(%s):%d 次%n", rank++, l.getImie(), l.getNazwisko(), l.getSpecjalnosc(), entry.getValue()); }
额外优化建议
- 替换
SimpleDateFormat为Java 8+的LocalDate和DateTimeFormatter,线程安全且API更友好。 - 将文件读取逻辑封装成独立工具方法(比如
loadLekarzeFromFile、loadPacjenciFromFile),让主方法更简洁。 - 添加异常细化处理,比如捕获
NumberFormatException,避免因文件中ID不是数字导致程序崩溃。
内容的提问来源于stack exchange,提问作者tryingmybest09
相关产品推荐
相关产品推荐

