7、抽象工厂模式:产品族与产品等级结构
抽象工厂模式,说实话,是我在实际项目中用得最多的创建型模式之一。它解决了一个很现实的问题:当你的系统需要支持多套产品组合时,怎么设计才能不崩?
我记得有一次接手一个电商后台系统,需要同时对接支付宝和微信支付,每种支付方式又有自己的退款、对账、通知机制。如果每个类都单独 new,那代码简直没法看。抽象工厂模式就是专门处理这种「多套产品组合」的利器。
产品族与产品等级结构
在讲抽象工厂之前,得先搞清楚两个概念:产品族和产品等级结构。这两个词听着绕,其实很好理解。
产品等级结构,说白了就是同一类产品的继承体系。比如「支付」是一个抽象接口,下面有「支付宝支付」「微信支付」这些具体实现。这就是一个产品等级结构。
产品族,指的是由同一个工厂生产的一组产品。比如「支付宝体系」包含支付宝支付、支付宝退款、支付宝对账——这些产品虽然功能不同,但都属于同一家。
你想想看,如果只有一种产品等级结构,用简单工厂或者工厂方法就够了。但一旦涉及多个产品等级结构之间的搭配,抽象工厂就派上用场了。
抽象工厂模式的定义
抽象工厂模式(Abstract Factory Pattern)提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
嗯,这里要注意:它和工厂方法模式最大的区别在于——工厂方法模式只生产一种产品,而抽象工厂模式生产一整套产品。
我个人的习惯是:当系统中存在多个产品等级结构,且这些产品需要组合使用时,优先考虑抽象工厂。比如 UI 组件库,Windows 风格下按钮、文本框、菜单是一套,Mac 风格下又是另一套。这两套之间不能混搭,对吧?
模式结构
抽象工厂模式包含以下几个角色:
- AbstractFactory(抽象工厂):声明创建一组产品对象的接口
- ConcreteFactory(具体工厂):实现抽象工厂,创建具体产品
- AbstractProduct(抽象产品):为每种产品声明接口
- ConcreteProduct(具体产品):实现抽象产品接口
- Client(客户端):仅依赖抽象工厂和抽象产品
SVG 结构图:抽象工厂模式核心逻辑
代码实现
咱们用支付场景来写个例子。假设系统需要支持支付宝和微信两套支付体系,每套体系包含支付和退款两个产品。
// 抽象产品:支付接口
public interface Payment {
void pay(double amount);
}
// 抽象产品:退款接口
public interface Refund {
void refund(double amount);
}
// 具体产品:支付宝支付
public class AlipayPayment implements Payment {
@Override
public void pay(double amount) {
System.out.println("支付宝支付:" + amount + "元");
}
}
// 具体产品:支付宝退款
public class AlipayRefund implements Refund {
@Override
public void refund(double amount) {
System.out.println("支付宝退款:" + amount + "元");
}
}
// 具体产品:微信支付
public class WechatPayment implements Payment {
@Override
public void pay(double amount) {
System.out.println("微信支付:" + amount + "元");
}
}
// 具体产品:微信退款
public class WechatRefund implements Refund {
@Override
public void refund(double amount) {
System.out.println("微信退款:" + amount + "元");
}
}
// 抽象工厂
public interface PaymentFactory {
Payment createPayment();
Refund createRefund();
}
// 具体工厂:支付宝工厂
public class AlipayFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new AlipayPayment();
}
@Override
public Refund createRefund() {
return new AlipayRefund();
}
}
// 具体工厂:微信工厂
public class WechatFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new WechatPayment();
}
@Override
public Refund createRefund() {
return new WechatRefund();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
// 根据配置选择工厂
PaymentFactory factory = new AlipayFactory();
// 或者 factory = new WechatFactory();
Payment payment = factory.createPayment();
Refund refund = factory.createRefund();
payment.pay(100.0);
refund.refund(50.0);
}
}
优缺点分析
| 优点 | 缺点 |
|---|---|
|
|
适用场景
- 系统需要独立于产品的创建、组合和表示
- 系统需要配置多套产品族中的一套
- 产品族内的产品需要一起使用,且这个约束需要被强制执行
- 你希望提供一组产品类库,只暴露接口而不是实现
说白了,当你发现代码里有一堆 if-else 在判断「用哪套方案」,而且每套方案都涉及多个类的创建时,抽象工厂模式就是你的解药。
嗯,最后说一句:抽象工厂和工厂方法经常被拿来比较。我的经验是——如果只涉及一个产品等级结构,用工厂方法就够了。一旦涉及多个产品等级结构的组合,才考虑抽象工厂。别一上来就上抽象工厂,过度设计也是坑。
公众号:蓝海资料掘金营,微信deep3321