Java 设计模式之工厂模式:对象创建的艺术(含 UML 图解)

Java 设计模式之工厂模式:对象创建的艺术(含 UML 图解)

Java 设计模式之工厂模式:对象创建的艺术(含 UML 图解)

在软件开发中,对象的创建是最基础也最频繁的操作。如果直接在代码中到处使用new关键字创建对象,会导致代码耦合度高、扩展性差。工厂模式(Factory Pattern)通过将对象创建的逻辑封装在专门的工厂类中,实现了 "创建与使用分离",是解决对象创建问题的经典方案。

工厂模式并非单一模式,而是一个模式家族,包含简单工厂模式、工厂方法模式和抽象工厂模式三种形式。本文将详细讲解这三种模式的实现与应用场景。

一、工厂模式的核心思想

工厂模式属于创建型设计模式,它的核心思想是:将对象的创建过程封装起来,让客户端无需关心对象的具体创建细节,只需通过工厂获取所需对象。

生活中的工厂模式例子随处可见:

汽车工厂生产不同品牌的汽车,消费者无需知道汽车的生产细节,直接从工厂提车即可

披萨店(工厂)制作不同口味的披萨,顾客只需点单(调用工厂方法),无需自己动手制作

工厂模式的核心价值在于:

降低耦合:客户端与具体产品解耦,只依赖工厂和抽象产品

提高扩展性:新增产品时只需扩展工厂,无需修改客户端

统一管理:对象创建逻辑集中在工厂,便于维护和控制

二、简单工厂模式(Simple Factory)

简单工厂模式是工厂模式中最基础的形式,它通过一个工厂类根据传入的参数决定创建哪种产品对象。

核心角色

抽象产品(Product):定义产品的公共接口

具体产品(Concrete Product):实现抽象产品接口,是工厂创建的目标

工厂(Factory):根据参数创建具体产品的实例

UML 类图

+------------------+

| Product |

+------------------+

| + operation(): void |

+------------------+

^

|

+------------------+ +------------------+

| ConcreteProductA | | ConcreteProductB |

+------------------+ +------------------+

| + operation(): void | | + operation(): void |

+------------------+ +------------------+

^ ^

| |

+------------------+

| Factory |

+------------------+

| + createProduct(type): Product |

+------------------+

代码实现:计算器工厂

以简单计算器为例,实现一个能创建加法、减法运算器的简单工厂:

1. 抽象产品(运算接口)

/**

* 抽象产品:运算接口

*/

public interface Operation {

double calculate(double a, double b);

}

2. 具体产品(加法、减法实现)

/**

* 具体产品:加法运算

*/

public class AddOperation implements Operation {

@Override

public double calculate(double a, double b) {

return a + b;

}

}

/**

* 具体产品:减法运算

*/

public class SubtractOperation implements Operation {

@Override

public double calculate(double a, double b) {

return a - b;

}

}

3. 工厂类(运算器工厂)

/**

* 简单工厂:运算器工厂

*/

public class OperationFactory {

/**

* 根据类型创建运算器

* @param type 运算类型:"+" "-"

* @return 具体运算器实例

*/

public static Operation createOperation(String type) {

Operation operation = null;

switch (type) {

case "+":

operation = new AddOperation();

break;

case "-":

operation = new SubtractOperation();

break;

default:

throw new IllegalArgumentException("不支持的运算类型");

}

return operation;

}

}

4. 客户端使用

public class Client {

public static void main(String[] args) {

// 从工厂获取加法运算器

Operation addOp = OperationFactory.createOperation("+");

System.out.println("3 + 5 = " + addOp.calculate(3, 5)); // 8.0

// 从工厂获取减法运算器

Operation subOp = OperationFactory.createOperation("-");

System.out.println("10 - 4 = " + subOp.calculate(10, 4)); // 6.0

}

}

简单工厂模式的优缺点

优点:实现简单,客户端无需知道产品创建细节

缺点:违反开闭原则,新增产品需修改工厂类的判断逻辑,工厂类职责过重

三、工厂方法模式(Factory Method)

为了解决简单工厂模式的缺陷,工厂方法模式将工厂抽象化,为每个产品创建对应的工厂类,使新增产品时只需扩展工厂,无需修改原有代码。

核心角色

抽象产品(Product):定义产品的公共接口

具体产品(Concrete Product):实现抽象产品接口

抽象工厂(Abstract Factory):定义创建产品的接口

具体工厂(Concrete Factory):实现抽象工厂接口,创建具体产品

UML 类图

+------------------+ +------------------+

| Product | | AbstractFactory |

+------------------+ +------------------+

| + operation(): void | | + createProduct(): Product |

+------------------+ +------------------+

^ ^

| |

+------------------+ +------------------+

| ConcreteProductA |<----->| FactoryA |

+------------------+ +------------------+

| + operation(): void | | + createProduct(): Product |

+------------------+ +------------------+

+------------------+ +------------------+

| ConcreteProductB |<----->| FactoryB |

+------------------+ +------------------+

| + operation(): void | | + createProduct(): Product |

+------------------+ +------------------+

代码实现:日志记录器工厂

以日志记录为例,实现文件日志和数据库日志的工厂方法模式:

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 fileFactory = new FileLoggerFactory();

Logger fileLogger = fileFactory.createLogger();

fileLogger.log("系统启动成功"); // 文件日志:系统启动成功

// 创建数据库日志工厂和日志记录器

LoggerFactory dbFactory = new DatabaseLoggerFactory();

Logger dbLogger = dbFactory.createLogger();

dbLogger.log("用户登录"); // 数据库日志:用户登录

}

}

工厂方法模式的优缺点

优点:符合开闭原则,新增产品只需新增对应的产品类和工厂类;单一职责,每个工厂只负责创建一种产品

缺点:类数量增多,系统复杂度提高;客户端需要知道具体工厂才能获取对应产品

四、抽象工厂模式(Abstract Factory)

当需要创建一系列相互关联或依赖的产品时,抽象工厂模式应运而生。它提供一个接口,用于创建多个产品族中的产品对象。

核心概念

产品族:同一工厂生产的、功能相关联的一组产品(如华为工厂生产的手机、平板)

产品等级结构:同一类产品的不同实现(如手机有华为手机、苹果手机)

核心角色

抽象产品(Abstract Product):多个产品等级结构的接口

具体产品(Concrete Product):实现抽象产品接口

抽象工厂(Abstract Factory):声明创建多个产品族的方法

具体工厂(Concrete Factory):实现抽象工厂,创建同一产品族的产品

UML 类图

+------------------+ +------------------+

| Phone | | Tablet |

+------------------+ +------------------+

| + call(): void | | + browse(): void |

+------------------+ +------------------+

^ ^

| |

+------------------+ +------------------+

| HuaweiPhone | | HuaweiTablet |

+------------------+ +------------------+

| + call(): void | | + browse(): void |

+------------------+ +------------------+

+------------------+ +------------------+

| IPhone | | IPad |

+------------------+ +------------------+

| + call(): void | | + browse(): void |

+------------------+ +------------------+

^ ^

| |

+------------------+

| AbstractFactory |

+------------------+

| + createPhone(): Phone |

| + createTablet(): Tablet |

+------------------+

^

|

+------------------+ +------------------+

| HuaweiFactory | | AppleFactory |

+------------------+ +------------------+

| + createPhone(): Phone | | + createPhone(): Phone |

| + createTablet(): Tablet | | + createTablet(): Tablet |

+------------------+ +------------------+

代码实现:电子设备工厂

以华为和苹果的产品族为例,实现能生产手机和平板的抽象工厂:

1. 抽象产品(手机、平板接口)

/**

* 抽象产品:手机

*/

public interface Phone {

void call();

}

/**

* 抽象产品:平板

*/

public interface Tablet {

void browse();

}

2. 具体产品(华为 / 苹果的手机和平板)

/**

* 具体产品:华为手机

*/

public class HuaweiPhone implements Phone {

@Override

public void call() {

System.out.println("用华为手机打电话");

}

}

/**

* 具体产品:华为平板

*/

public class HuaweiTablet implements Tablet {

@Override

public void browse() {

System.out.println("用华为平板浏览网页");

}

}

/**

* 具体产品:苹果手机

*/

public class IPhone implements Phone {

@Override

public void call() {

System.out.println("用iPhone打电话");

}

}

/**

* 具体产品:苹果平板

*/

public class IPad implements Tablet {

@Override

public void browse() {

System.out.println("用iPad浏览网页");

}

}

3. 抽象工厂(电子设备工厂接口)

/**

* 抽象工厂:电子设备工厂

*/

public interface ElectronicFactory {

Phone createPhone(); // 生产手机

Tablet createTablet();// 生产平板

}

4. 具体工厂(华为工厂、苹果工厂)

/**

* 具体工厂:华为工厂

*/

public class HuaweiFactory implements ElectronicFactory {

@Override

public Phone createPhone() {

return new HuaweiPhone();

}

@Override

public Tablet createTablet() {

return new HuaweiTablet();

}

}

/**

* 具体工厂:苹果工厂

*/

public class AppleFactory implements ElectronicFactory {

@Override

public Phone createPhone() {

return new IPhone();

}

@Override

public Tablet createTablet() {

return new IPad();

}

}

5. 客户端使用

public class Client {

public static void main(String[] args) {

// 使用华为工厂生产华为产品族

ElectronicFactory huaweiFactory = new HuaweiFactory();

Phone huaweiPhone = huaweiFactory.createPhone();

Tablet huaweiTablet = huaweiFactory.createTablet();

huaweiPhone.call(); // 用华为手机打电话

huaweiTablet.browse(); // 用华为平板浏览网页

// 使用苹果工厂生产苹果产品族

ElectronicFactory appleFactory = new AppleFactory();

Phone iPhone = appleFactory.createPhone();

Tablet iPad = appleFactory.createTablet();

iPhone.call(); // 用iPhone打电话

iPad.browse(); // 用iPad浏览网页

}

}

抽象工厂模式的优缺点

优点:便于管理同一产品族的产品;保证产品族内产品的兼容性;符合开闭原则(扩展产品族只需新增工厂)

缺点:扩展新的产品等级结构困难(如新增手表产品,需修改所有工厂接口和实现)

五、三种工厂模式的对比与选择

模式

核心特点

适用场景

优缺点对比

简单工厂

一个工厂类创建所有产品

产品种类少,变化不频繁

实现简单但违反开闭原则

工厂方法

一个工厂对应一个产品

产品种类较多,需要灵活扩展

符合开闭原则但类数量增多

抽象工厂

一个工厂创建一个产品族

需要创建相互关联的产品组,强调产品族兼容性

适合产品族扩展,但难扩展新产品

选择建议:

简单场景用简单工厂,快速实现

单一产品扩展用工厂方法,兼顾灵活与简单

多产品族场景用抽象工厂,保证产品关联性

六、工厂模式在 Java 中的应用

JDK 中的应用:

java.util.Calendar:通过getInstance()方法(简单工厂)创建日历实例

java.sql.DriverManager:通过getConnection()获取不同数据库连接(工厂方法)

java.net.URLStreamHandlerFactory:创建不同协议的流处理器(抽象工厂)

框架中的应用:

Spring 的BeanFactory:通过工厂模式创建和管理 Bean 对象

MyBatis 的SqlSessionFactory:创建SqlSession对象(工厂方法)

总结

工厂模式通过封装对象创建逻辑,完美诠释了 "创建与使用分离" 的设计思想。从简单工厂到抽象工厂,模式的复杂度逐渐增加,但灵活性和适用性也随之提升。

在实际开发中,不必盲目追求复杂模式,应根据业务场景选择最合适的实现:简单场景用简单工厂提高开发效率,复杂场景用工厂方法或抽象工厂保证扩展性。记住,设计模式的核心是解决问题,而非炫技。

掌握工厂模式,不仅能写出更优雅的代码,更能培养 "封装变化" 的设计思维 —— 这正是优秀程序员与普通程序员的重要区别。

相关推荐

微信群活码二维码制作指南:教你如何生成永久有效群二维码
「蟾」字组词
365BET导航

「蟾」字组词

📅 10-22 👁️ 5145
涨乐财富通开户国债逆回购怎么买?发布时间:2024-2-1 14:49阅读:1517
为什么连续五年没有大年三十
365BET导航

为什么连续五年没有大年三十

📅 11-13 👁️ 1930
大主播都不想搞直播带货了
365bet投注盘口

大主播都不想搞直播带货了

📅 10-16 👁️ 2092
禊的形近字
365BET导航

禊的形近字

📅 10-16 👁️ 8421