核心是用策略注册表替代硬编码工厂,通过统一fileparser接口和concurrenthashmap实现运行时动态解析;所有解析器无状态、supports()仅校验后缀或魔数,注册于启动阶段,业务代码零耦合具体类型。

核心是把“根据文件类型创建解析器”这件事,从 if-else 或 switch 里抽出来,变成运行时由类型自己决定行为。硬编码工厂的问题在于:每加一种文件格式(比如新增 .xlsx 或 .avro),就得改工厂类、重新编译、可能影响其他分支——这在高并发场景下尤其危险,容易引发类加载竞争或配置热更失败。
定义统一解析接口,不依赖具体实现
先聚焦“它们都要做什么”,而不是“现在有哪些格式”。例如:
- 声明 FileParser 接口,含
parse(InputStream)和supports(String fileName) - 所有解析器(CsvParser、JsonParser、XmlParser)都实现它,
supports()只判断后缀或魔数,不查数据库、不读配置 - 接口方法参数用通用类型(如
InputStream、Map<string object></string>),避免每个实现传一堆定制 DTO
用策略注册表替代条件分支
把原来散落在工厂里的 if-else 收拢成一个线程安全的映射容器:
- 用
ConcurrentHashMap<string fileparser></string>存"csv" → new CsvParser()、"json" → new JsonParser() - 注册动作放在启动阶段(如 Spring 的
@PostConstruct或静态代码块),避免运行时写冲突 - 解析时只调
registry.getOrDefault(ext, fallback).parse(input),无判断、无锁、无分支
让工厂退居幕后,业务代码彻底不见 new 和类型名
工厂不该暴露创建逻辑,更不该被业务类直接 new:
- 业务类(如
ImportService)通过构造器接收FileParserRegistry,不持有任何具体解析器引用 - 不写
instanceof、不做强制转换、不根据扩展名手动 new —— 这些都是解耦失败的信号 - 若需动态加载(如插件化支持新格式),用
ServiceLoader或 Spring 的@ConditionalOnProperty控制自动装配,而非修改主工厂
高并发下特别注意的细节
多态本身轻量,但初始化和注册环节容易成为瓶颈:
- 所有解析器实例应是无状态的(stateless),可安全共享;有状态字段(如缓存、连接池)必须通过构造参数注入,且确保线程安全
- 避免在
parse()方法里做耗时 IO 或同步块;大文件解析建议配合CompletableFuture或响应式流 - 注册表 key 统一转小写并 trim 空格(
fileName.substring(lastDot+1).toLowerCase().trim()),防止因大小写或空格导致 miss 缓存











