本文目录导读:

从快递点餐系统看透Java抽象工厂模式:解耦与扩展的终极实战
目录导读
- 引言:为什么快递点餐系统需要抽象工厂?
场景痛点:业务对象族的创建依赖关系混乱
- 抽象工厂模式的核心概念与结构
产品等级结构 vs 产品族:用点餐举例说明
- 快递点餐系统案例分析
- 需求定义:可切换的“快递公司+支付方式”组合
- 代码实现:抽象工厂、具体工厂、产品接口
- 与传统工厂模式的区别(高频面试题)
工厂方法 vs 抽象工厂:适用场景对比
- 抽象工厂模式的优缺点与SEO优化建议
关键词:低耦合、高内聚、扩展性、产品族
- 常见问题问答(Q&A)
- Q1:如何增加新的产品族而不修改客户端代码?
- Q2:抽象工厂与Spring IOC的关系?
引言:为什么快递点餐系统需要抽象工厂?
假设你要设计一个快递点餐系统——用户在线订餐,选择“顺丰配送+微信支付”或“美团配送+支付宝支付”,如果直接用new创建对象,每当新增快递公司(如京东物流)或支付方式(如银联云闪付),就必须修改大量业务代码。
痛点总结:
- 产品之间互相约束(比如顺丰只支持微信支付)
- 需要保证同一产品族(快递+支付)的兼容性
- 未来扩展会频繁修改现有代码(违反开闭原则)
抽象工厂模式正是为了解决“创建一组相关或相互依赖的对象”而生,在Java开发中,它是实现跨平台界面组件、多数据库切换、多供应商API适配的核心设计模式。
抽象工厂模式的核心概念与结构
1 产品等级结构 vs 产品族
以快递点餐为例:
- 产品等级结构:快递接口(Delivery)、支付接口(Payment)
- 产品族:顺丰族(SFDelivery+WechatPay)、美团族(MeituanDelivery+Alipay)
抽象工厂模式的关键是:让一个工厂负责创建一个产品族中的所有产品,而不是单个产品。
2 标准类图(四要素)
- AbstractFactory:声明创建快递、支付的抽象方法
- ConcreteFactory(如SFExpressFactory):实现具体产品族的创建
- AbstractProduct(Delivery/Payment接口)
- Client:通过抽象工厂引用,只需知道产品族类型,无需关心具体类名
快递点餐系统案例分析
1 需求定义
系统需要支持两种配送-支付组合:
- 组合A:顺丰快递 + 微信支付 (针对高端用户)
- 组合B:美团配送 + 支付宝支付 (针对大众用户)
未来可能新增“京东物流+银联支付”组合。
2 代码实现(伪代码+关键逻辑)
// 步骤1:定义抽象产品接口
public interface Delivery {
void deliver();
}
public interface Payment {
void pay();
}
// 步骤2:实现具体产品(顺丰族)
public class SFDelivery implements Delivery {
public void deliver() { System.out.println("顺丰配送中..."); }
}
public class WechatPay implements Payment {
public void pay() { System.out.println("微信支付成功"); }
}
// 步骤3:定义抽象工厂
public interface ExpressFactory {
Delivery createDelivery();
Payment createPayment();
}
// 步骤4:实现具体工厂(顺丰族工厂)
public class SFExpressFactory implements ExpressFactory {
public Delivery createDelivery() { return new SFDelivery(); }
public Payment createPayment() { return new WechatPay(); }
}
// 步骤5:客户端调用(只需知道工厂类型)
public class Client {
public static void main(String[] args) {
ExpressFactory factory = new SFExpressFactory(); // 可替换为美团工厂
Delivery delivery = factory.createDelivery();
Payment payment = factory.createPayment();
delivery.deliver();
payment.pay();
// 输出:顺丰配送中... 微信支付成功
}
}
关键点说明:
- 使用
ExpressFactory接口,客户端完全不依赖具体快递或支付类名 - 新增“京东+银联”只需要新增一个
JDExpressFactory实现类,无需修改Client代码
与传统工厂模式的区别
| 对比维度 | 工厂方法模式 | 抽象工厂模式 |
|---|---|---|
| 创建对象 | 单个产品 | 产品族(多个产品) |
| 层级 | 简单工厂→工厂方法(属于类级别) | 对象级别(属于集合) |
| 扩展性 | 每新增一个产品需要加一个工厂 | 每新增一个产品族需要加一个工厂,不涉及修改现有工厂 |
| 适用场景 | 单一产品体系(如各种Logger) | 多产品相互关联(如UI组件、物流支付) |
典型面试题: “你见过哪些JDK源码使用了抽象工厂?”
javax.xml.parsers.DocumentBuilderFactory(获取XML解析器)java.sql.Connection(不同数据库的Connection创建)- Spring的
BeanFactory配合FactoryBean实现产品族
抽象工厂模式的优缺点与SEO优化建议
1 优点
- 解耦:客户端无需知道具体产品类名,降低模块依赖
- 产品族一致性:保证同一工厂生产的产品相互兼容(如顺丰配送必须配合微信支付,不会出现顺丰+支付宝的错误组合)
- 符合开闭原则:新增产品族时,只需添加新工厂和产品类,无需修改客户端代码
2 缺点
- 复杂度高:每增加一个产品等级结构(如新增“短信通知”产品),所有具体工厂都需要修改
- 不适合简单场景:如果只有一个产品等级结构,直接用工厂方法更简洁
3 SEO写作优化技巧(针对技术博客)
- 关键词密度:保持“Java抽象工厂模式”出现3-5次,“快递点餐系统”作为实际场景用例出现6-8次,自然融入文中
- 外链思维:可以内链到“工厂方法模式对比”“Java设计模式六大原则”等关联文章
- 段落结构:用H2/H3标题分割,每段不超过150字,便于爬虫抓取
常见问题问答(Q&A)
Q1:如何增加新的产品族而不修改客户端代码?
客户端代码中只要不出现new ConcreteFactory(),而是通过配置文件+反射或Spring依赖注入来获取工厂实例:
// 通过配置文件加载工厂类名
String factoryClass = config.getProperty("express.factory");
ExpressFactory factory = (ExpressFactory) Class.forName(factoryClass).newInstance();
使用Spring框架时,可以通过@Autowired自动装配ExpressFactory接口,并根据配置文件决定使用哪个实现类,这体现了控制反转的核心思想。
Q2:抽象工厂与Spring IOC容器是什么关系?
Spring IOC本身不是抽象工厂模式,但它可以实现抽象工厂的效果:
- 通过
BeanFactory的getBean方法创建产品 - 通过
@Qualifier或@Primary在多个实现类中选择 - 当你需要创建一组相互关联的Bean(如数据源+事务管理器+连接池),可以通过
@Configuration类模拟抽象工厂的存在
快递点餐系统案例完美展示了抽象工厂如何解决“产品族创建”的耦合问题,在实际的Java企业开发中,跨数据库迁移(Oracle-H2-MySQL连接池切换)、多支付通道集成(微信-支付宝-银联)都是抽象工厂的最佳应用场景,理解它,你就能写出更灵活、更易扩展的K8s(微服务)适配代码。
(全文约1420字,未包含字数统计)