读取含Employee子类信息的多行文件,现有代码求优化方案
优化员工数据加载代码的实用建议
看起来你已经搞定了基础的员工数据读取和泛型集合存储功能,但肯定是觉得当前的实现可能有点臃肿(比如一堆条件判断创建子类对象),想让代码更优雅、易维护对吧?结合你的场景——Employee父类下有三个子类,从文件读取每行不同格式的数据并实例化对应的对象——我给你几个实际项目里常用的优化思路:
1. 用工厂模式封装对象创建逻辑,让加载方法更清爽
把判断员工类型、创建对应子类对象的逻辑抽离到一个专门的工厂类里,这样loadData方法只需要专注于读取文件和调用工厂,代码结构更清晰,以后加新的员工类型也不用大改加载方法。
举个例子:
// 专门负责创建员工对象的工厂类 public class EmployeeFactory { public static Employee createEmployee(String[] dataParts) { // 假设每行数据的第4个字段是员工类型标识(比如HOURLY/SALARY/COMMISSION) String empType = dataParts[3]; switch(empType) { case "HOURLY": return new Hourly(dataParts[0], dataParts[1], dataParts[2], Double.parseDouble(dataParts[4]), Double.parseDouble(dataParts[5])); case "SALARY": return new Salary(dataParts[0], dataParts[1], dataParts[2], Double.parseDouble(dataParts[4])); case "COMMISSION": return new Commission(dataParts[0], dataParts[1], dataParts[2], Double.parseDouble(dataParts[4]), Double.parseDouble(dataParts[5])); default: throw new IllegalArgumentException("不认识的员工类型: " + empType); } } } // 优化后的loadData方法 public void loadData(File inFile) throws IOException { // 用try-with-resources自动关闭Scanner,避免忘记关资源导致泄漏 try (Scanner in = new Scanner(inFile)) { List<Employee> employees = new ArrayList<>(); while (in.hasNextLine()) { String line = in.nextLine().trim(); if (line.isEmpty()) continue; // 跳过空行 // 假设数据用逗号分隔,拆分每行成字段数组 String[] dataParts = line.split(","); Employee emp = EmployeeFactory.createEmployee(dataParts); employees.add(emp); } } }
这里用try-with-resources是个小细节,比手动写finally关闭Scanner更安全省心。
2. 让每个子类自己负责解析数据,解耦更彻底
可以给每个Employee子类加一个静态的工厂方法,让子类自己处理数据解析和对象创建,工厂类只需要调用对应子类的方法就行。这样每个类只管好自己的事,符合单一职责原则。
比如Hourly子类可以这么写:
public class Hourly extends Employee { // 父类继承来的构造方法 public Hourly(String name, String empNum, String dept, double hourlyRate, double hoursWorked) { super(name, empNum, dept); // 初始化子类自己的字段 } // 静态方法:从数据数组创建Hourly对象 public static Hourly fromData(String[] dataParts) { return new Hourly(dataParts[0], dataParts[1], dataParts[2], Double.parseDouble(dataParts[4]), Double.parseDouble(dataParts[5])); } }
然后工厂类就可以简化成:
public class EmployeeFactory { public static Employee createEmployee(String[] dataParts) { String empType = dataParts[3]; return switch(empType) { case "HOURLY" -> Hourly.fromData(dataParts); case "SALARY" -> Salary.fromData(dataParts); case "COMMISSION" -> Commission.fromData(dataParts); default -> throw new IllegalArgumentException("不认识的员工类型: " + empType); }; } }
以后新增员工类型,只需要加对应的子类和在工厂里加一行case就行,改动很小。
3. 用映射表替代冗长的switch/case(进阶优化)
如果以后员工类型越来越多,一堆switch/case会显得很乱,这时候可以用一个Map来存储“类型标识”和对应的创建逻辑,代码会更简洁,扩展性也更好:
public class EmployeeFactory { // 提前把所有员工类型的创建逻辑存在Map里 private static final Map<String, Function<String[], Employee>> EMPLOYEE_CREATORS = Map.of( "HOURLY", Hourly::fromData, "SALARY", Salary::fromData, "COMMISSION", Commission::fromData ); public static Employee createEmployee(String[] dataParts) { String empType = dataParts[3]; // 从Map里拿对应的创建函数 Function<String[], Employee> creator = EMPLOYEE_CREATORS.get(empType); if (creator == null) { throw new IllegalArgumentException("不认识的员工类型: " + empType); } return creator.apply(dataParts); } }
以后加新类型,只需要在Map里加一组键值对就行,完全不用修改createEmployee的逻辑,完美符合开闭原则。
几个额外的小建议
- 异常处理:解析数值的时候(比如
parseDouble)容易抛出NumberFormatException,建议在工厂方法里捕获或者包装成自定义异常,方便上层处理错误数据。 - 数据验证:创建对象前先检查一下数据是否完整(比如字段数量够不够、数值是否合法),别创建出无效的员工对象。
- 面向接口编程:尽量用
List<Employee>而不是ArrayList<Employee>来声明集合,以后想换成其他List实现(比如LinkedList)也不用改代码。
内容的提问来源于stack exchange,提问作者Shah Bari
相关产品推荐
相关产品推荐

