工厂模式
...大约 6 分钟设计模式
工厂模式的核心思想是我不直接创建对象,而是让一个专门的‘工厂’帮我创建对象。”**这样做的好处是代码更加灵活,扩展性更强,而且可以隐藏对象的创建细节。
工厂模式的核心概念
- 客户端(Client):需要使用对象的地方。
- 工厂(Factory):负责创建对象的地方。
- 产品(Product):被创建的对象。
工厂模式的类型
工厂模式有几种变体,比如简单工厂模式、工厂方法模式和抽象工厂模式。我们先从最简单的开始讲起。
1. 简单工厂模式
场景
假设你开了一家冰淇淋店,顾客可以点不同口味的冰淇淋。如果你直接在代码中写:
if (flavor.equals("vanilla")) {
return new VanillaIceCream();
} else if (flavor.equals("chocolate")) {
return new ChocolateIceCream();
}
这样代码会很混乱,而且每次新增口味都要修改代码。这时候就可以用简单工厂模式。
实现代码
// 产品接口:冰淇淋
interface IceCream {
void eat();
}
// 具体产品:香草冰淇淋
class VanillaIceCream implements IceCream {
@Override
public void eat() {
System.out.println("吃了一碗香草冰淇淋!");
}
}
// 具体产品:巧克力冰淇淋
class ChocolateIceCream implements IceCream {
@Override
public void eat() {
System.out.println("吃了一碗巧克力冰淇淋!");
}
}
// 工厂类:冰淇淋工厂
class IceCreamFactory {
public static IceCream createIceCream(String flavor) {
if (flavor == null) {
return null;
}
if (flavor.equalsIgnoreCase("vanilla")) {
return new VanillaIceCream();
} else if (flavor.equalsIgnoreCase("chocolate")) {
return new ChocolateIceCream();
} else {
return null;
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 客户端不需要直接创建对象,而是通过工厂获取
IceCream iceCream = IceCreamFactory.createIceCream("vanilla");
iceCream.eat(); // 输出:吃了一碗香草冰淇淋!
IceCream anotherIceCream = IceCreamFactory.createIceCream("chocolate");
anotherIceCream.eat(); // 输出:吃了一碗巧克力冰淇淋!
}
}
大白话解释
- 产品:冰淇淋,有香草味和巧克力味。
- 工厂:冰淇淋工厂,负责根据顾客的需求(香草味或巧克力味)创建对应的冰淇淋。
- 客户端:顾客,只需要告诉工厂要什么口味,工厂会帮你准备好。
好处:如果未来要增加草莓味冰淇淋,只需要在工厂里加一个分支:
else if (flavor.equalsIgnoreCase("strawberry")) {
return new StrawberryIceCream();
}
不需要修改客户端代码。
2. 工厂方法模式
场景
简单工厂模式看起来很好,但如果冰淇淋的种类越来越多,工厂类会变得很臃肿(很多 if-else
)。工厂方法模式则把创建对象的逻辑分散到不同的子类中。
实现代码
// 产品接口:冰淇淋
interface IceCream {
void eat();
}
// 具体产品:香草冰淇淋
class VanillaIceCream implements IceCream {
@Override
public void eat() {
System.out.println("吃了一碗香草冰淇淋!");
}
}
// 具体产品:巧克力冰淇淋
class ChocolateIceCream implements IceCream {
@Override
public void eat() {
System.out.println("吃了一碗巧克力冰淇淋!");
}
}
// 工厂接口:冰淇淋工厂
interface IceCreamFactory {
IceCream createIceCream();
}
// 具体工厂:香草冰淇淋工厂
class VanillaIceCreamFactory implements IceCreamFactory {
@Override
public IceCream createIceCream() {
return new VanillaIceCream();
}
}
// 具体工厂:巧克力冰淇淋工厂
class ChocolateIceCreamFactory implements IceCreamFactory {
@Override
public IceCream createIceCream() {
return new ChocolateIceCream();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 客户端通过具体的工厂来创建对象
IceCreamFactory vanillaFactory = new VanillaIceCreamFactory();
IceCream vanillaIceCream = vanillaFactory.createIceCream();
vanillaIceCream.eat(); // 输出:吃了一碗香草冰淇淋!
IceCreamFactory chocolateFactory = new ChocolateIceCreamFactory();
IceCream chocolateIceCream = chocolateFactory.createIceCream();
chocolateIceCream.eat(); // 输出:吃了一碗巧克力冰淇淋!
}
}
大白话解释
- 工厂接口:冰淇淋工厂的通用接口,定义了“创建冰淇淋”的方法。
- 具体工厂:每个口味的冰淇淋都有自己的工厂(香草工厂、巧克力工厂)。每个工厂只负责创建一种冰淇淋。
- 客户端:顾客只需要选择一个工厂(比如香草工厂),工厂会自动帮你创建对应的冰淇淋。
好处:如果新增草莓冰淇淋,只需要新增一个 StrawberryIceCream
类和一个 StrawberryIceCreamFactory
类,不需要修改现有代码。这样代码的扩展性更好。
3. 抽象工厂模式
场景
假设你的冰淇淋店不仅卖冰淇淋,还卖冰沙。简单工厂和工厂方法模式只能创建同一种类型的产品(比如只创建冰淇淋)。抽象工厂模式则可以同时创建多种相关的产品(比如同时创建冰淇淋和冰沙)。
实现代码
// 冰淇淋接口
interface IceCream {
void eat();
}
// 香草冰淇淋
class VanillaIceCream implements IceCream {
@Override
public void eat() {
System.out.println("吃了一碗香草冰淇淋!");
}
}
// 巧克力冰淇淋
class ChocolateIceCream implements IceCream {
@Override
public void eat() {
System.out.println("吃了一碗巧克力冰淇淋!");
}
}
// 冰沙接口
interface Slush {
void drink();
}
// 香草冰沙
class VanillaSlush implements Slush {
@Override
public void drink() {
System.out.println("喝了一杯香草冰沙!");
}
}
// 巧克力冰沙
class ChocolateSlush implements Slush {
@Override
public void drink() {
System.out.println("喝了一杯巧克力冰沙!");
}
}
// 抽象工厂接口
interface DessertFactory {
IceCream createIceCream();
Slush createSlush();
}
// 香草工厂
class VanillaFactory implements DessertFactory {
@Override
public IceCream createIceCream() {
return new VanillaIceCream();
}
@Override
public Slush createSlush() {
return new VanillaSlush();
}
}
// 巧克力工厂
class ChocolateFactory implements DessentFactory {
@Override
public IceCream createIceCream() {
return new ChocolateIceCream();
}
@Override
public Slush createSlush() {
return new ChocolateSlush();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 选择香草工厂
DessertFactory vanillaFactory = new VanillaFactory();
IceCream vanillaIceCream = vanillaFactory.createIceCream();
Slush vanillaSlush = vanillaFactory.createSlush();
vanillaIceCream.eat(); // 输出:吃了一碗香草冰淇淋!
vanillaSlush.drink(); // 输出:喝了一杯香草冰沙!
// 选择巧克力工厂
DessertFactory chocolateFactory = new ChocolateFactory();
IceCream chocolateIceCream = chocolateFactory.createIceCream();
Slush chocolateSlush = chocolateFactory.createSlush();
chocolateIceCream.eat(); // 输出:吃了一碗巧克力冰淇淋!
chocolateSlush.drink(); // 输出:喝了一杯巧克力冰沙!
}
}
大白话解释
- 产品族:冰淇淋和冰沙是一对相关的产品,香草工厂可以同时生产香草冰淇淋和香草冰沙,巧克力工厂可以同时生产巧克力冰淇淋和巧克力冰沙。
- 抽象工厂接口:定义了“创建冰淇淋”和“创建冰沙”的方法。
- 具体工厂:每个工厂(香草工厂、巧克力工厂)都可以创建一组相关的产品。
- 客户端:顾客只需要选择一个工厂,就可以同时获得冰淇淋和冰沙。
好处:如果新增草莓口味,只需要新增一个草莓工厂,而不需要修改现有代码。同时,抽象工厂模式可以创建一组相关的产品,而不是单一的产品。
总结
- 简单工厂模式:用一个工厂类来创建对象,但扩展性较差(太多
if-else
)。 - 工厂方法模式:用多个工厂类
4. 实际java开发中,有哪些常用的工厂模式呢
1. Spring 框架
BeanFactory
和ApplicationContext
:Spring 的核心功能之一,通过配置(注解或XML)动态创建和管理Bean。客户端代码通过工厂获取Bean实例,而无需关心具体的创建细节。
DriverManager
2. JDBC 的 - 数据库连接工厂:
DriverManager
根据数据库URL、用户名和密码,动态创建数据库连接(Connection
)。客户端代码只需要调用DriverManager.getConnection()
,而无需直接管理连接的创建过程。