核心思路是通过接口定义统一行为契约,方法参数声明为该契约类型,实际传入任意具体实现类,从而实现业务逻辑复用与开闭原则;例如导出功能定义Exporter接口及Excel/Pdf/Csv实现类,清洗服务定义DataReader接口及MySql/Json/Csv实现类,配合工厂或Spring注入动态选择实现,且严禁强制转型以维持封装性。

核心思路是:用接口或抽象类定义统一行为契约,方法参数声明为该契约类型,实际传入任意具体实现——这样业务逻辑只写一次,新增类型只需加个类,不碰原有代码。
用接口收拢不同类型的处理入口
比如导出订单,要支持 Excel、PDF、CSV 三种格式。别写三个方法 exportToExcel()、exportToPdf()、exportToCsv()。而是定义一个接口:
- interface Exporter { void export(Order order); }
- ExcelExporter、PdfExporter、CsvExporter 各自实现 export() 方法
- 业务方法只接收 Exporter 类型:void doExport(Exporter exporter, Order order) { exporter.export(order); }
调用时传哪个实现类,就执行哪种导出逻辑。加新格式?只写新实现类,方法签名和调用方全都不动。
让多态参数自动适配异构数据源
系统要对接多种外部数据:MySQL 查询结果、HTTP 接口返回的 JSON、本地 CSV 文件。它们结构不同,但都有“读取一批记录”的共性。
- 定义 interface DataReader { List
read(); } - MySqlReader、JsonReader、CsvReader 分别实现 read(),内部各自解析逻辑
- 清洗服务统一接收 DataReader:void clean(DataReader reader) { List
data = reader.read(); /* 统一清洗逻辑 */ }
不管上游是数据库还是 API,清洗模块完全不用改。数据源变了?换一个实现类传进去就行。
配合工厂或配置动态选择具体实现
硬编码 new ExcelExporter() 不利于扩展。更实用的做法是结合配置或简单工厂:
- 根据请求参数 type=excel,调用 ExporterFactory.getExporter("excel") 返回对应实例
- Spring 环境下直接注入 @Qualifier("pdfExporter") Exporter exporter
- 甚至用策略模式 + Map
预注册所有类型,查表即得
这样上层业务代码彻底与实现解耦,连 new 都看不见,切换行为只需改配置或注册项。
注意边界:只调用契约内方法,避免强制转型
多态参数的好处是“只关注能做什么”,不是“它到底是什么”。所以:
- Exporter 参数只能调用 export(),不能假设它是 ExcelExporter 就去调 getSheetName()
- 如果真需要子类特有功能,应在接口里明确扩展方法(如 addHeader()),而不是在业务方法里 instanceof 判断后强转
- 否则破坏封装,新增类型又要改这里,多态就失效了
保持参数类型干净,才是长期可维护的关键。

















