小张的工厂进化史——工厂模式
小张从华强北起家,最初只有一条组装线,根据订单参数(手机/平板)手动切换生产流程。随着订单量激增,他经历了三次产业升级:
- 阶段1:全能生产线通过指令切换产品(简单工厂模式)
- 阶段2:引入代工厂分品牌生产(工厂方法模式)
- 阶段3:打造生态产品族统一管理(抽象工厂模式)
一、简单工厂模式:全能生产线
场景:小张初期用一条生产线,通过参数指令生产不同电子产品。
代码示例:
// 抽象产品:电子设备接口
public interface Device {
void boot();
}
// 具体产品:手机
public class Phone implements Device {
@Override
public void boot() {
System.out.println("【简单工厂】手机开机:Android系统启动");
}
}
// 具体产品:平板
public class Tablet implements Device {
@Override
public void boot() {
System.out.println("【简单工厂】平板开机:Android系统启动");
}
}
// 简单工厂类
public class ElectronicsFactory {
public static Device createDevice(String type) {
if ("phone".equalsIgnoreCase(type)) {
return new Phone();
} else if ("tablet".equalsIgnoreCase(type)) {
return new Tablet();
}
throw new IllegalArgumentException("不支持的设备类型");
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
Device phone = ElectronicsFactory.createDevice("phone");
phone.boot(); // 输出:手机开机...
}
}
特点:
- 参数化创建:通过
if-else
判断生产设备,违反开闭原则(新增产品需修改工厂类) - 适用场景:初期产品线单一(如仅手机和平板)
二、工厂方法模式:分品牌代工
场景:小张引入华为、小米代工厂,各品牌独立生产设备。
代码示例:
// 抽象工厂接口
public interface DeviceFactory {
Device createDevice();
}
// 具体工厂:华为代工厂
public class HuaweiFactory implements DeviceFactory {
@Override
public Device createDevice() {
return new HuaweiPhone(); // 华为手机
}
}
// 具体产品:华为手机
public class HuaweiPhone implements Device {
@Override
public void boot() {
System.out.println("【工厂方法】华为手机:HarmonyOS启动");
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
DeviceFactory factory = new HuaweiFactory();
Device phone = factory.createDevice();
phone.boot(); // 输出:华为手机...
}
}
特点:
- 多态扩展:新增品牌(如OPPO)只需添加新工厂类,符合开闭原则
- 类爆炸:每新增一个品牌需增加2个类(工厂+产品)
三、抽象工厂模式:生态产品族
场景:小张扩展生态链,生产同一品牌的多类产品(手机+耳机),确保设计兼容。
代码示例:
// 抽象工厂接口
public interface BrandFactory {
Phone createPhone();
Earphones createEarphones();
}
// 具体工厂:苹果生态
public class AppleFactory implements BrandFactory {
@Override
public Phone createPhone() {
return new iPhone(); // 苹果手机
}
@Override
public Earphones createEarphones() {
return new AirPods(); // 苹果耳机
}
}
// 关联产品族
public class iPhone implements Phone {
@Override
public void boot() {
System.out.println("【抽象工厂】iPhone开机:iOS启动");
}
}
public class AirPods implements Earphones {
public void connect() {
System.out.println("【抽象工厂】AirPods自动配对");
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
BrandFactory factory = new AppleFactory();
factory.createPhone().boot(); // 输出:iPhone开机...
factory.createEarphones().connect(); // 输出:AirPods自动配对...
}
}
特点:
- 产品族兼容:确保同一品牌风格统一(如苹果极简设计)
- 接口膨胀:新增品牌需实现全套接口(如华为生态需实现createPhone()和createEarphones())
四、三种模式核心对比表
简单工厂模式 | 工厂方法模式 | 抽象工厂模式 | |
---|---|---|---|
核心目标 | 快速生产单一产品 | 分品牌灵活扩展 | 创建兼容的生态产品族 |
扩展性 | ❌ 差(需修改代码) | ✅ 优(新增工厂类) | ❌ 差(需实现全套接口) |
类复杂度 | 1工厂类 + N产品类 | N工厂类 + N产品类 | M工厂类 + M×N产品类 |
设计原则 | 违反开闭原则 | 符合开闭原则 | 符合接口隔离原则 |
适用场景 | 初期单一产线(手机/平板) | 多品牌代工(华为/小米) | 生态链产品(苹果手机+耳机) |
五、结合Spring实现简单工厂(实践)
详细内容可参考:【当模板方法模式遇上工厂模式:一道优雅的烹饪架构设计】
抽象类(或者 接口)
public abstract class AbstractCooking {
protected CookEnum cookEnum;
protected abstract void aromaBlasting();
}
枚举类
/**
* 菜品枚举类
*/
public enum CookEnum {
KUNG_PAO_CHICKEN("kungPaoChicken", "宫保鸡丁"),
MAPO_TO_FU("mapoTofu", "麻婆豆腐");
private final String code;
private final String name;
CookEnum(String code, String name) {
this.code = code;
this.name = name;
}
....
}
宫保鸡丁
/**
* 宫保鸡丁
*/
@Service
public class KungPaoChicken extends AbstractCooking {
public KungPaoChicken() {
this.cookEnum = CookEnum.KUNG_PAO_CHICKEN;
}
@Override
protected void aromaBlasting() {
System.out.println("葱姜蒜爆香");
}
}
麻婆豆腐
/**
* 麻婆豆腐
*/
@Service
public class MapoTofu extends AbstractCooking {
public MapoTofu() {
this.cookEnum = CookEnum.MAPO_TO_FU;
}
@Override
protected void aromaBlasting() {
System.out.println("煸炒郫县豆瓣酱+花椒粒");
}
}
工厂类
@Service
public class CookFactory implements InitializingBean {
// Spring启动时,会依赖注入 所有的AbstractCooking的bean,注入到cookings
@Autowired
private List<AbstractCooking> cookings;
// 定义Map存储 bean的映射关系
private Map<CookEnum, AbstractCooking> cookingMap = new HashMap<>();
public AbstractCooking getCookingByCode(String code) {
CookEnum cookEnum = CookEnum.getByCode(code);
return cookingMap.get(cookEnum);
}
// CookFactory的bean对象在初始化阶段,动态把 AbstractCooking的所有bean 设置到cookingMap (动态扩展的关键)
@Override
public void afterPropertiesSet() throws Exception {
for (AbstractCooking cooking: cookings) {
cookingMap.put(cooking.getCookEnum(), cooking);
}
}
}