Java 工厂模式详解
在软件开发中,对象的创建是一个基本操作。但直接在代码中使用 new 关键字创建对象会导致代码耦合度高、可维护性差。工厂模式(Factory Pattern)作为一种创建型设计模式,能有效解决这些问题。本文将深入探讨 Java 中的工厂模式,通过实例展示其实现方式、优势及适用场景。
一、工厂模式的定义与概念
工厂模式的核心思想是:将对象的创建和使用分离,把对象创建逻辑封装在一个工厂类中,从而提高代码的可维护性和可扩展性。
工厂模式主要分为三种类型:
- 第一种:简单工厂模式(Simple Factory):不属于23种设计模式之一。简单工厂模式又叫做:静态 工厂方法模式。简单工厂模式是工厂方法模式的一种特殊实现。
- 第二种:工厂方法模式(Factory Method):是23种设计模式之一。
- 第三种:抽象工厂模式(Abstract Factory):是23种设计模式之一。
二、简单工厂模式
简单工厂模式是工厂模式的基础版本,它定义了一个工厂类来创建产品对象。
-
抽象产品 角色
-
具体产品 角色
-
工厂类 角色
示例1:兵工厂
抽象产品 角色:Weapon
public abstract class Weapon {
/**
* 所有的武器都可以攻击。
*/
public abstract void attack();
}
具体产品 角色:Dagger、Fighter、Tank
public class Dagger extends Weapon{
@Override
public void attack() {
System.out.println("砍丫的!!!");
}
}
public class Fighter extends Weapon{
@Override
public void attack() {
System.out.println("战斗机抛下小男孩!!!!");
}
}
public class Tank extends Weapon{
@Override
public void attack() {
System.out.println("坦克开炮!!!");
}
}
工厂类 角色
public class WeaponFactory {
/**
* 静态方法。要获取什么产品?就看你传什么参数,传TANK获取坦克,传DAGGER获取匕首,传FIGHTER获取战斗机
* 简单工厂模式中有一个静态方法,所以被称为:静态工厂方法模式。
* @param weaponType
* @return
*/
public static Weapon get(String weaponType){
if ("TANK".equals(weaponType)) {
return new Tank();
} else if ("DAGGER".equals(weaponType)) {
return new Dagger();
} else if ("FIGHTER".equals(weaponType)) {
return new Fighter();
} else {
throw new RuntimeException("不支持该武器的生产");
}
}
}
测试:
public class Test {
public static void main(String[] args) {
// 需要坦克
// 对于我客户端来说,坦克的生产细节,我不需要关心,我只需要向工厂索要即可。
// 简单工厂模式达到了什么呢?职责分离。客户端不需要关心产品的生产细节。
// 客户端只负责消费。工厂类负责生产。一个负责生产,一个负责消费。生产者和消费者分离了。这就是简单工厂模式的作用。
Weapon tank = WeaponFactory.get("TANK");
tank.attack();
// 需要匕首
Weapon dagger = WeaponFactory.get("DAGGER");
dagger.attack();
// 需要战斗机
Weapon fighter = WeaponFactory.get("FIGHTER");
fighter.attack();
}
}

简单工厂模式的缺点?
缺点一:假设现在需要扩展一个新的产品,WeaponFactory工厂类的代码是需要修改的,显然违背了OCP原则。
缺点二:工厂类的责任比较重大,不能出现任何问题,因为这个工厂类负责所有产品的生产,称为全能类,或者有人把它叫做上帝类。
这个工厂类一旦出问题,整个系统必然全部瘫痪。(不要把所有鸡蛋放到一个篮子里面哦。)
示例2:交通工具工厂示例
假设我们正在开发一个模拟城市交通系统的游戏,需要创建不同类型的交通工具(汽车、自行车、公交车)。使用简单工厂模式可以这样设计:
定义产品接口
// 交通工具接口
public interface Vehicle {
void drive();
int getMaxSpeed();
}
实现具体产品类
// 汽车
public class Car implements Vehicle {
@Override
public void drive() {
System.out.println("驾驶汽车在公路上行驶");
}
@Override
public int getMaxSpeed() {
return 180;
}
}
// 自行车
public class Bicycle implements Vehicle {
@Override
public void drive() {
System.out.println("骑自行车在自行车道上行驶");
}
@Override
public int getMaxSpeed() {
return 25;
}
}
// 公交车
public class Bus implements Vehicle {
@Override
public void drive() {
System.out.println("驾驶公交车在城市线路上行驶");
}
@Override
public int getMaxSpeed() {
return 80;
}
}
创建简单工厂类
// 交通工具工厂
public class VehicleFactory {
public static Vehicle createVehicle(String vehicleType) {
if (vehicleType == null) {
return null;
}
return switch (vehicleType.toLowerCase()) {
case "car" -> new Car();
case "bicycle" -> new Bicycle();
case "bus" -> new Bus();
default -> throw new IllegalArgumentException("未知的交通工具类型: " + vehicleType);
};
}
}
客户端使用
public class Client {
public static void main(String[] args) {
// 创建汽车
Vehicle car = VehicleFactory.createVehicle("car");
car.drive();
System.out.println("最高速度: " + car.getMaxSpeed() + " km/h");
// 创建自行车
Vehicle bicycle = VehicleFactory.createVehicle("bicycle");
bicycle.drive();
System.out.println("最高速度: " + bicycle.getMaxSpeed() + " km/h");
// 创建公交车
Vehicle bus = VehicleFactory.createVehicle("bus");
bus.drive();
System.out.println("最高速度: " + bus.getMaxSpeed() + " km/h");
}
}

简单工厂模式的优缺点:
- 优点:实现简单,将对象创建和使用分离。
- 缺点:工厂类职责过重,新增产品需修改工厂类,违反开闭原则。
三、工厂方法模式
工厂方法模式将对象创建延迟到子类,每个具体工厂类负责创建特定类型的产品。
工厂方法模式既保留了简单工厂模式的优点,同时又解决了简单工厂模式的缺点。 工厂方法模式的角色包括:
-
抽象工厂角色
-
具体工厂角色
-
抽象产品角色
-
具体产品角色
示例1:兵工厂
就是把工厂开成专门的坦克制造厂和飞机制造厂,各种厂抽象出一个接口厂
抽象产品角色 Weapon
abstract public class Weapon {
public abstract void attack();
}
具体产品角色 Dagger Gun
public class Dagger extends Weapon{
@Override
public void attack() {
System.out.println("砍丫的!!!");
}
}
public class Gun extends Weapon{
@Override
public void attack() {
System.out.println("开枪射击!!!");
}
}
抽象工厂角色 WeaponFactory
abstract public class WeaponFactory {
/**
* 这个方法不是静态的。是实例方法。
* @return
*/
public abstract Weapon get();
}
具体工厂角色 DaggerFactory GunFactory
public class GunFactory extends WeaponFactory{
@Override
public Weapon get() {
return new Gun();
}
}
public class DaggerFactory extends WeaponFactory{
@Override
public Weapon get() {
return new Dagger();
}
}
Test
public class Test {
public static void main(String[] args) {
WeaponFactory weaponFactory = new DaggerFactory();
Weapon dagger = weaponFactory.get();
dagger.attack();
WeaponFactory weaponFactory1 = new GunFactory();
Weapon gun = weaponFactory1.get();
gun.attack();
}
}

如果想扩展一个新的产品,只要新增一个产品类,再新增一个该产品对应的工厂即可,例如新增:战斗机
public class Fighter extends Weapon{
@Override
public void attack() {
System.out.println("战斗机发射核弹!");
}
}
public class FighterFactory extends WeaponFactory{
@Override
public Weapon get() {
return new Fighter();
}
}
客户端程序:
public class Client {
public static void main(String[] args) {
WeaponFactory factory = new GunFactory();
Weapon weapon = factory.get();
weapon.attack();
WeaponFactory factory1 = new FighterFactory();
Weapon weapon1 = factory1.get();
weapon1.attack();
WeaponFactory factory2 = new DaggerFactory();
Weapon weapon2 = factory2.get();
weapon2.attack();
}
}
执行结果如下:

我们可以看到在进行功能扩展的时候,不需要修改之前的源代码,显然工厂方法模式符合OCP原则。
工厂方法模式的优点:
一个调用者想创建一个对象,只要知道其名称就可以了。
扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
屏蔽产品的具体实现,调用者只关心产品的接口。
工厂方法模式的缺点:
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
示例2:日志记录器工厂
假设我们需要创建不同类型的日志记录器(文件日志、数据库日志),使用工厂方法模式可以这样设计:
步骤 1:定义产品接口
// 日志记录器接口
public interface Logger {
void log(String message);
}
步骤 2:实现具体产品类
// 文件日志记录器
public class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("文件日志: " + message);
}
}
// 数据库日志记录器
public class DatabaseLogger implements Logger {
@Override
public void log(String message) {
System.out.println("数据库日志: " + message);
}
}
步骤 3:定义工厂接口
// 日志记录器工厂接口
public interface LoggerFactory {
Logger createLogger();
}
步骤 4:实现具体工厂类
// 文件日志工厂
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new FileLogger();
}
}
// 数据库日志工厂
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new DatabaseLogger();
}
}
步骤 5:客户端使用
public class Client {
public static void main(String[] args) {
// 创建文件日志工厂
LoggerFactory fileLoggerFactory = new FileLoggerFactory();
Logger fileLogger = fileLoggerFactory.createLogger();
fileLogger.log("这是文件日志");
// 创建数据库日志工厂
LoggerFactory databaseLoggerFactory = new DatabaseLoggerFactory();
Logger databaseLogger = databaseLoggerFactory.createLogger();
databaseLogger.log("这是数据库日志");
}
}
输出结果:
文件日志: 这是文件日志
数据库日志: 这是数据库日志
四、抽象工厂模式
示例1:兵工厂
抽象工厂模式相对于工厂方法模式来说,就是工厂方法模式是针对一个产品系列的,而抽象工厂模式是针对多个产品系列的,即工厂方法模式是一个产品系列一个工厂类,而抽象工厂模式是多个产品系列一个工厂类。
抽象工厂中包含4个角色:
- 抽象工厂角色
- 具体工厂角色
- 抽象产品角色
- 具体产品角色
抽象工厂模式的类图如下:

抽象工厂模式代码如下:
第一部分:武器产品族
public abstract class Weapon {
public abstract void attack();
}
public class Gun extends Weapon{
@Override
public void attack() {
System.out.println("开枪射击!");
}
}
public class Dagger extends Weapon{
@Override
public void attack() {
System.out.println("砍丫的!");
}
}
第二部分:水果产品族
public abstract class Fruit {
/**
* 所有果实都有一个成熟周期。
*/
public abstract void ripeCycle();
}
public class Orange extends Fruit{
@Override
public void ripeCycle() {
System.out.println("橘子的成熟周期是10个月");
}
}
public class Apple extends Fruit{
@Override
public void ripeCycle() {
System.out.println("苹果的成熟周期是8个月");
}
}
第四部分:具体工厂类
public class WeaponFactory extends AbstractFactory{
public Weapon getWeapon(String type){
if (type == null || type.trim().length() == 0) {
return null;
}
if ("Gun".equals(type)) {
return new Gun();
} else if ("Dagger".equals(type)) {
return new Dagger();
} else {
throw new RuntimeException("无法生产该武器");
}
}
@Override
public Fruit getFruit(String type) {
return null;
}
}
public class FruitFactory extends AbstractFactory{
@Override
public Weapon getWeapon(String type) {
return null;
}
public Fruit getFruit(String type){
if (type == null || type.trim().length() == 0) {
return null;
}
if ("Orange".equals(type)) {
return new Orange();
} else if ("Apple".equals(type)) {
return new Apple();
} else {
throw new RuntimeException("我家果园不产这种水果");
}
}
}
第五部分:客户端程序
public class Client {
public static void main(String[] args) {
// 客户端调用方法时只面向AbstractFactory调用方法。
AbstractFactory factory = new WeaponFactory(); // 注意:这里的new WeaponFactory()可以采用 简单工厂模式 进行隐藏。
Weapon gun = factory.getWeapon("Gun");
Weapon dagger = factory.getWeapon("Dagger");
gun.attack();
dagger.attack();
AbstractFactory factory1 = new FruitFactory(); // 注意:这里的new FruitFactory()可以采用 简单工厂模式 进行隐藏。
Fruit orange = factory1.getFruit("Orange");
Fruit apple = factory1.getFruit("Apple");
orange.ripeCycle();
apple.ripeCycle();
}
}
执行结果:

抽象工厂模式的优缺点:
-
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
-
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在AbstractFactory里加代码,又要在具体的里面加代码。
示例2:UI 组件工厂
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
假设我们需要创建不同风格的 UI 组件(按钮、文本框),使用抽象工厂模式可以这样设计:
步骤 1:定义产品接口
// 按钮接口
public interface Button {
void paint();
}
// 文本框接口
public interface TextField {
void display();
}
步骤 2:实现具体产品类
// Windows 风格按钮
public class WindowsButton implements Button {
@Override
public void paint() {
System.out.println("绘制 Windows 风格按钮");
}
}
// macOS 风格按钮
public class MacOSButton implements Button {
@Override
public void paint() {
System.out.println("绘制 macOS 风格按钮");
}
}
// Windows 风格文本框
public class WindowsTextField implements TextField {
@Override
public void display() {
System.out.println("显示 Windows 风格文本框");
}
}
// macOS 风格文本框
public class MacOSTextField implements TextField {
@Override
public void display() {
System.out.println("显示 macOS 风格文本框");
}
}
步骤 3:定义抽象工厂接口
// UI 组件工厂接口
public interface GUIFactory {
Button createButton();
TextField createTextField();
}
步骤 4:实现具体工厂类
// Windows 风格 UI 工厂
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextField createTextField() {
return new WindowsTextField();
}
}
// macOS 风格 UI 工厂
public class MacOSFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacOSButton();
}
@Override
public TextField createTextField() {
return new MacOSTextField();
}
}
步骤 5:客户端使用
public class Client {
public static void main(String[] args) {
// 创建 Windows 风格 UI 工厂
GUIFactory windowsFactory = new WindowsFactory();
Button windowsButton = windowsFactory.createButton();
TextField windowsTextField = windowsFactory.createTextField();
windowsButton.paint();
windowsTextField.display();
// 创建 macOS 风格 UI 工厂
GUIFactory macosFactory = new MacOSFactory();
Button macosButton = macosFactory.createButton();
TextField macosTextField = macosFactory.createTextField();
macosButton.paint();
macosTextField.display();
}
}
输出结果:
绘制 Windows 风格按钮
显示 Windows 风格文本框
绘制 macOS 风格按钮
显示 macOS 风格文本框
抽象工厂模式的优缺点:
- 优点:将具体产品创建封装,客户端无需依赖具体产品类。
- 缺点:扩展产品族困难,新增产品需修改抽象工厂接口及所有子类。
五、三种工厂模式的对比
| 模式 | 工厂类 / 接口 | 产品创建逻辑 | 扩展性 |
|---|---|---|---|
| 简单工厂 | 具体类(静态方法) | 集中在工厂类中 | 新增产品需修改工厂类,违反开闭原则 |
| 工厂方法 | 抽象接口 + 具体工厂类 | 由具体工厂类实现 | 新增产品只需添加新的具体工厂类 |
| 抽象工厂 | 抽象接口 + 具体工厂类 | 由具体工厂类实现多个相关产品 | 新增产品族容易,新增单个产品困难 |
六、Java 中工厂模式的实际应用
示例:数据库连接工厂
// 数据库连接接口
public interface DBConnection {
void connect();
}
// MySQL 连接
public class MySQLConnection implements DBConnection {
@Override
public void connect() {
System.out.println("连接到 MySQL 数据库");
}
}
// Oracle 连接
public class OracleConnection implements DBConnection {
@Override
public void connect() {
System.out.println("连接到 Oracle 数据库");
}
}
// 数据库连接工厂
public class DBConnectionFactory {
public static DBConnection getConnection(String dbType) {
if (dbType == null) {
return null;
}
if (dbType.equalsIgnoreCase("MYSQL")) {
return new MySQLConnection();
} else if (dbType.equalsIgnoreCase("ORACLE")) {
return new OracleConnection();
}
throw new IllegalArgumentException("不支持的数据库类型: " + dbType);
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
DBConnection mysqlConn = DBConnectionFactory.getConnection("MYSQL");
mysqlConn.connect();
DBConnection oracleConn = DBConnectionFactory.getConnection("ORACLE");
oracleConn.connect();
}
}
七、总结
工厂模式是一种非常实用的创建型设计模式,它将对象的创建和使用分离,提高了代码的可维护性和可扩展性。在实际开发中,可以根据需求选择合适的工厂模式:
- 简单工厂:适用于创建对象逻辑简单且产品种类较少的场景。
- 工厂方法:适用于需要扩展性,经常新增产品的场景。
- 抽象工厂:适用于创建一系列相关产品的场景。
通过合理应用工厂模式,可以构建更加灵活、可维护的软件系统。
更多推荐



所有评论(0)