基于Apache POI与OpenCSV的文件读取器设计模式优化问询
解决方案:优化文件读取模块的接口设计与模式应用
针对你遇到的接口方法冗余问题,以下几种设计思路和模式可以解决该问题:
1. 基于泛型的通用接口(单一职责)
将接口改为泛型化设计,让实现类仅处理自身支持的DTO类型,避免冗余方法:
定义泛型接口
public interface FileReadable<T> { void open(String filePath); void close(); List<T> read(Class<T> dtoType); }
CsvReader实现
public class CsvReader implements FileReadable<Object> { private CSVReader csvReader; @Override public void open(String filePath) { // 初始化OpenCSV读取器逻辑 } @Override public void close() { // 关闭资源逻辑 } @Override @SuppressWarnings("unchecked") public List<Object> read(Class<?> dtoType) { if (dtoType == CsvDto1.class) { return (List<Object>) readCsvDto1(); } else if (dtoType == CsvDto2.class) { return (List<Object>) readCsvDto2(); } throw new IllegalArgumentException("不支持的DTO类型"); } // 原get1()逻辑封装为私有方法 private List<CsvDto1> readCsvDto1() { // 读取并转换为CsvDto1列表 } // 原get2()逻辑封装为私有方法 private List<CsvDto2> readCsvDto2() { // 读取并转换为CsvDto2列表 } }
ExcelReader的实现逻辑类似,仅处理ExlDto1和ExlDto2类型即可。
2. 接口拆分(接口隔离原则)
把原有的大接口拆分为多个职责单一的小接口,让实现类仅实现自身需要的接口:
定义拆分后的接口
// 通用文件操作接口(仅包含open/close) public interface FileOperable { void open(String filePath); void close(); } // CSV专属读取接口 public interface CsvReadable extends FileOperable { List<CsvDto1> get1(); List<CsvDto2> get2(); } // Excel专属读取接口 public interface ExcelReadable extends FileOperable { List<ExlDto1> get3(); List<ExlDto2> get4(); }
实现类适配
public class CsvReader implements CsvReadable { // 实现open、close、get1、get2方法 } public class ExcelReader implements ExcelReadable { // 实现open、close、get3、get4方法 }
这种方式完全避免了冗余方法,每个实现类只承担自身的职责。
3. 策略+工厂模式(统一调用入口)
如果业务层需要统一的调用方式,可以用策略模式封装不同DTO的读取逻辑,配合工厂模式根据文件和DTO类型获取对应的策略:
定义策略接口
public interface ReadStrategy<T> { void open(String filePath); void close(); List<T> read(); }
实现具体策略
// CsvDto1读取策略 public class CsvDto1Strategy implements ReadStrategy<CsvDto1> { private CSVReader csvReader; @Override public void open(String filePath) { // 初始化逻辑 } @Override public void close() { // 关闭逻辑 } @Override public List<CsvDto1> read() { // 读取CsvDto1的具体逻辑 } } // 同理实现CsvDto2Strategy、ExlDto1Strategy、ExlDto2Strategy
工厂类获取策略
public class ReadStrategyFactory { @SuppressWarnings("unchecked") public static <T> ReadStrategy<T> getStrategy(Class<T> dtoType, String filePath) { if (dtoType == CsvDto1.class && filePath.endsWith(".csv")) { return (ReadStrategy<T>) new CsvDto1Strategy(); } else if (dtoType == CsvDto2.class && filePath.endsWith(".csv")) { return (ReadStrategy<T>) new CsvDto2Strategy(); } else if (dtoType == ExlDto1.class && filePath.endsWith(".xlsx")) { return (ReadStrategy<T>) new ExlDto1Strategy(); } else if (dtoType == ExlDto2.class && filePath.endsWith(".xlsx")) { return (ReadStrategy<T>) new ExlDto2Strategy(); } throw new IllegalArgumentException("不支持的文件或DTO类型"); } }
业务层调用示例
ReadStrategy<CsvDto1> strategy = ReadStrategyFactory.getStrategy(CsvDto1.class, "data.csv"); strategy.open("data.csv"); List<CsvDto1> dataList = strategy.read(); strategy.close();
4. 适配器模式(兼容原有代码)
如果不想修改已有的CsvReader和ExcelReader结构,可以用适配器模式将它们适配到通用接口:
定义通用接口
public interface GenericReader<T> { void open(String filePath); void close(); List<T> read(); }
实现适配器
// CsvDto1的适配器 public class CsvDto1Adapter implements GenericReader<CsvDto1> { private CsvReader csvReader; public CsvDto1Adapter(CsvReader csvReader) { this.csvReader = csvReader; } @Override public void open(String filePath) { csvReader.open(filePath); } @Override public void close() { csvReader.close(); } @Override public List<CsvDto1> read() { return csvReader.get1(); } }
通过适配器,既保留原有类的逻辑,又能适配到统一接口,避免冗余方法暴露。
内容的提问来源于stack exchange,提问作者Hola
相关产品推荐
相关产品推荐

