工厂模式
- 🍔 为什么需要工厂模式?
- 简单工厂模式
- 💡 核心思想
- 🛠️ 代码实现
- 📊 优缺点分析
- 工厂方法模式
- 💡 核心思想
- 🛠️ 代码实现
- 📊 优缺点分析
- 抽象工厂模式
- 💡 核心思想
- 🛠️ 代码实现
- 📊 优缺点分析
- 🧠 总结与对比
🍔 为什么需要工厂模式?
假设你开了一家咖啡店,代码是这样写的:
publicclassCoffeeStore{publicCoffeeorderCoffee(Stringtype){Coffeecoffee=null;if("americano".equals(type)){coffee=newAmericano();}elseif("latte".equals(type)){coffee=newLatte();}// 加糖加奶...returncoffee;}}问题来了:如果现在要加一种卡布奇诺,必须修改orderCoffee方法的源码,这违反了开闭原则(对扩展开放,对修改关闭)。而且,咖啡店不仅负责卖咖啡,还负责生产咖啡,职责不单一。
这时候,我们把生产咖啡的活儿剥离出去,交给专门的工厂来做。
简单工厂模式
简单工厂其实不属于 GoF 23 种设计模式,但它太常用了,可以说是工厂模式的入门。
💡 核心思想
定义一个工厂类,根据传入的参数不同,返回不同的对象实例。
🛠️ 代码实现
// 1. 定义咖啡接口publicinterfaceCoffee{voidmake();}// 2. 具体咖啡实现publicclassAmericanoimplementsCoffee{@Overridepublicvoidmake(){System.out.println("制作美式咖啡...");}}publicclassLatteimplementsCoffee{@Overridepublicvoidmake(){System.out.println("制作拿铁咖啡...");}}// 3. 简单工厂类 (核心)publicclassSimpleCoffeeFactory{publicstaticCoffeecreateCoffee(Stringtype){if("americano".equals(type)){returnnewAmericano();}elseif("latte".equals(type)){returnnewLatte();}else{thrownewIllegalArgumentException("没有这种咖啡");}}}// 4. 咖啡店(客户端)publicclassCoffeeStore{publicCoffeeorderCoffee(Stringtype){// 咖啡店不自己生产,交给工厂Coffeecoffee=SimpleCoffeeFactory.createCoffee(type);coffee.make();returncoffee;}}📊 优缺点分析
- 优点:客户端(CoffeeStore)免除了直接创建对象的职责,解除了与具体产品的耦合。
- 缺点:违背了开闭原则。每增加一种咖啡,都要修改
SimpleCoffeeFactory里的if-else。工厂类的职责过重。
工厂方法模式
为了解决简单工厂违背开闭原则的问题,我们升级一下。
💡 核心思想
定义一个用于创建对象的接口(抽象工厂),让子类决定实例化哪个类。将对象实例化推迟到子类。
🛠️ 代码实现
// 1. 抽象工厂接口publicinterfaceCoffeeFactory{CoffeecreateCoffee();}// 2. 具体工厂实现publicclassAmericanoFactoryimplementsCoffeeFactory{@OverridepublicCoffeecreateCoffee(){returnnewAmericano();}}publicclassLatteFactoryimplementsCoffeeFactory{@OverridepublicCoffeecreateCoffee(){returnnewLatte();}}// 3. 咖啡店(客户端)publicclassCoffeeStore{// 聚合工厂接口,不再依赖具体工厂privateCoffeeFactoryfactory;publicCoffeeStore(CoffeeFactoryfactory){this.factory=factory;}publicCoffeeorderCoffee(){Coffeecoffee=factory.createCoffee();coffee.make();returncoffee;}}客户端调用:
// 想喝美式,就开一家美式工厂注入进去CoffeeStorestore=newCoffeeStore(newAmericanoFactory());store.orderCoffee();// 想喝拿铁,换一家拿铁工厂store=newCoffeeStore(newLatteFactory());store.orderCoffee();📊 优缺点分析
- 优点:完美符合开闭原则。新增咖啡种类?只需要新增一个
Coffee实现类和一个对应的CoffeeFactory实现类,完全不用改原有代码! - 缺点:类的数量成倍增加(每个产品对应一个工厂)。在系统复杂度较低时,这种设计显得有些“重”。
抽象工厂模式
如果现在需求又升级了:咖啡店不仅要卖咖啡,还要卖甜点!而且美式要配提拉米苏,拿铁要配抹茶蛋糕(它们是有组合关系的)。
这时候用工厂方法就需要建一堆工厂,管理起来很乱。抽象工厂登场!
💡 核心思想
提供一个创建一系列相关或相互依赖对象的接口,而不指定它们具体的类。
🛠️ 代码实现
// 1. 定义甜点接口publicinterfaceDessert{voidshow();}// 2. 具体甜点publicclassTiramisuimplementsDessert{@Overridepublicvoidshow(){System.out.println("意大利提拉米苏");}}publicclassMatchaCakeimplementsDessert{@Overridepublicvoidshow(){System.out.println("抹茶蛋糕");}}// 3. 抽象工厂 (现在是产品族的工厂了)publicinterfaceItalianDessertFactory{CoffeecreateCoffee();DessertcreateDessert();}// 4. 具体工厂 (美式风味工厂)publicclassAmericanStyleFactoryimplementsItalianDessertFactory{@OverridepublicCoffeecreateCoffee(){returnnewAmericano();}@OverridepublicDessertcreateDessert(){returnnewTiramisu();}}// 5. 具体工厂 (拿铁风味工厂)publicclassLatteStyleFactoryimplementsItalianDessertFactory{@OverridepublicCoffeecreateCoffee(){returnnewLatte();}@OverridepublicDessertcreateDessert(){returnnewMatchaCake();}}客户端调用:
// 买一套美式风味套餐ItalianDessertFactoryfactory=newAmericanStyleFactory();Coffeecoffee=factory.createCoffee();Dessertdessert=factory.createDessert();coffee.make();dessert.show();📊 优缺点分析
- 优点:当一个产品族(如咖啡+甜点)需要一起使用时,它能保证客户端始终使用同一个族中的对象。
- 缺点:规定了所有可能被创建的产品集合,扩展新产品(比如新增“杯子”维度)非常困难,需要修改抽象工厂接口及其所有实现类,严重违背开闭原则。
🧠 总结与对比
别被这三个名字绕晕,记住下面这张表:
| 模式 | 核心特征 | if-else在哪? | 扩展新产品 | 扩展新产品族 | 适用场景 |
|---|---|---|---|---|---|
| 简单工厂 | 一个具体工厂,生产所有产品 | 在工厂类里 | 需改工厂代码 | 不支持 | 产品少,逻辑简单 |
| 工厂方法 | 一个抽象工厂,每个产品一个具体工厂 | 没有了 | 增加具体工厂即可 | 不支持 | 产品种类经常扩展 |
| 抽象工厂 | 一个抽象工厂,生产一个产品族 | 没有了 | 非常困难 | 增加具体工厂即可 | 固定的产品族体系(如UI换肤) |