Java 工厂设计模式
模式定义
工厂模式是一种创建对象的设计模式,它提供了一种创建对象的接口,使得客户端无需知道具体的创建细节,只需通过该接口就能获取所需的对象。
工厂模式主要解决了以下几个典型问题:
- 解耦:将对象的创建过程与使用过程分离,使得两者之间的耦合度降低,提高了系统的灵活性和可维护性。
- 灵活性:通过抽象工厂类或工厂方法,可以方便地扩展和添加新的产品对象,而不需要修改现有代码。
- 可配置性:可以通过配置文件或其他方式动态地决定创建哪种具体的产品对象,提高了系统的可配置性。
- 隐藏实现细节:客户端无需关心对象的具体创建过程和内部结构,只需使用工厂提供的接口,隐藏了实现细节,提高了代码的可读性和可维护性。
例如,在一个汽车制造工厂中,工厂模式可以用于创建不同类型的汽车,而无需让客户直接了解汽车的制造过程。客户只需告诉工厂他们需要的汽车类型,工厂就会创建相应的汽车对象。
模式分类
工厂模式有多种变体,如简单工厂模式、工厂方法模式和抽象工厂模式等,每种变体都有其适用的场景和特点。在实际应用中,需要根据具体的需求选择合适的工厂模式。
简单工厂模式
简单工厂模式也被称为静态工厂方法模式,它通常是一个静态方法,用于根据传入的参数来决定创建哪一个产品的实例。这种模式的优点是客户端可以免除直接创建产品对象的职责,很方便地创建出相应的产品。然而,它的缺点也很明显,例如工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。此外,使用简单工厂模式会增加系统中类的个数,增加系统的复杂度和理解难度。

代码示例
package com.binge._11_design_model.FactoryModel.factorymodel.SimpleFactory;
/**
* @author binge
* @Description 简单工厂模式案例
* @date 2024年03月11日 下午 12:01
*/
// 汽车接口
interface Car {
void drive();
}
// 具体汽车类:跑车
class SportsCar implements Car {
@Override
public void drive() {
System.out.println("跑车正在行驶...");
}
}
// 具体汽车类:轿车
class Sedan implements Car {
@Override
public void drive() {
System.out.println("轿车正在行驶...");
}
}
// 工厂类
class CarFactory {
public static Car createCar(String type) {
if ("跑车".equalsIgnoreCase(type)) {
return new SportsCar();
} else if ("轿车".equalsIgnoreCase(type)) {
return new Sedan();
} else {
throw new IllegalArgumentException("无效的汽车类型");
}
}
}
public class SimpleFactoryPatternExample {
public static void main(String[] args) {
// 创建跑车
Car sportsCar = CarFactory.createCar("跑车");
sportsCar.drive();
// 创建轿车
Car sedan = CarFactory.createCar("轿车");
sedan.drive();
}
}
在上述示例中,我们定义了一个Car接口,它有一个drive方法。然后,我们创建了两个具体的汽车类SportsCar和Sedan,它们都实现了Car接口。CarFactory是工厂类,它有一个createCar方法,根据传递的汽车类型字符串来创建相应的汽车对象。
在main方法中,我们使用工厂方法创建了跑车和轿车对象,并调用它们的drive方法来模拟汽车行驶。
通过使用简单工厂模式,我们将汽车的创建过程封装在工厂类中,使得客户端无需关心具体的创建细节,只需提供汽车类型即可获得相应的汽车对象。这样可以提高代码的灵活性和可维护性。
工厂方法模式
工厂方法模式是对简单工厂模式的进一步抽象化,它将工厂逻辑分散到各个子类中,使得系统在不修改原来代码的情况下可以引进新的产品,从而满足开闭原则。这种方式的好处是,当增加新产品时,只需要增加一个新的工厂类,而不需要修改原有的代码。

代码示例
// 汽车接口
interface Car {
void drive();
}
// 跑车类
class SportsCar implements Car {
@Override
public void drive() {
System.out.println("跑车正在行驶...");
}
}
// 轿车类
class Sedan implements Car {
@Override
public void drive() {
System.out.println("轿车正在行驶...");
}
}
// 工厂接口
interface CarFactory {
Car createCar();
}
// 跑车工厂类
class SportsCarFactory implements CarFactory {
@Override
public Car createCar() {
return new SportsCar();
}
}
// 轿车工厂类
class SedanFactory implements CarFactory {
@Override
public Car createCar() {
return new Sedan();
}
}
public class FactoryMethodPatternExample {
public static void main(String[] args) {
// 创建跑车工厂
CarFactory sportsCarFactory = new SportsCarFactory();
// 创建跑车
Car sportsCar = sportsCarFactory.createCar();
sportsCar.drive();
// 创建轿车工厂
CarFactory sedanFactory = new SedanFactory();
// 创建轿车
Car sedan = sedanFactory.createCar();
sedan.drive();
}
}
在这个示例中,我们首先定义了一个Car接口和两个具体的汽车类SportsCar和Sedan。然后,定义了一个CarFactory接口和两个具体的工厂类SportsCarFactory和SedanFactory。
在main方法中,我们创建了跑车工厂和轿车工厂,并通过它们创建相应的跑车和轿车对象。最后,调用汽车对象的drive方法来模拟汽车行驶。
通过使用工厂方法模式,我们将汽车的创建过程与具体的工厂类解耦,使得系统更加灵活和可扩展。如果需要添加新的汽车类型,只需要创建相应的工厂类和汽车类即可。
抽象工厂模式
抽象工厂模式则是更进一步的抽象化,它允许一个工厂接口创建一系列相关的对象,而无需指定它们的具体类。这种方式的好处是,可以在不修改客户端代码的情况下更换和添加新的具体产品类。

代码示例
package com.binge._11_design_model.FactoryModel.factorymodel.AbstractFactory;
/**
* @author binge
* @Description 抽象工厂案例
* @date 2024年03月11日 下午 12:24
*/
// 汽车接口
interface ICar {
void drive();
}
// 跑车抽象类
abstract class AbstractSportsCar implements ICar {
}
// 具体跑车类(宝马)
class BMWSportsCar extends AbstractSportsCar {
@Override
public void drive() {
System.out.println("宝马跑车正在行驶...");
}
}
// 具体跑车类(奔驰)
class BenzSportsCar extends AbstractSportsCar {
@Override
public void drive() {
System.out.println("奔驰跑车正在行驶...");
}
}
// 轿车抽象类
abstract class AbstractSedanCar implements ICar {
}
// 具体轿车类(宝马)
class BMWSedanCar extends AbstractSedanCar {
@Override
public void drive() {
System.out.println("宝马轿车正在行驶...");
}
}
// 具体轿车类(奔驰)
class BenzSedanCar extends AbstractSedanCar {
@Override
public void drive() {
System.out.println("奔驰轿车正在行驶...");
}
}
// 抽象工厂类
interface AbstractFactory {
AbstractSportsCar createSportsCar();
AbstractSedanCar createSedanCar();
}
// 宝马汽车工厂类
class BMWCarFactory implements AbstractFactory {
@Override
public AbstractSportsCar createSportsCar() {
return new BMWSportsCar();
}
@Override
public AbstractSedanCar createSedanCar() {
return new BMWSedanCar();
}
}
// 奔驰骑车工厂类
class BenzCarFactory implements AbstractFactory {
@Override
public AbstractSportsCar createSportsCar() {
return new BenzSportsCar();
}
@Override
public AbstractSedanCar createSedanCar() {
return new BenzSedanCar();
}
}
public class AbstractFactoryPatternExample {
public static void main(String[] args) {
// 创建宝马工厂
AbstractFactory bMWCarFactory = new BMWCarFactory();
// 创建跑车
AbstractSportsCar sportsCar = bMWCarFactory.createSportsCar();
sportsCar.drive();
// 创建小轿车
AbstractSedanCar sedanCar = bMWCarFactory.createSedanCar();
sedanCar.drive();
// 创建奔驰工厂
AbstractFactory benzCarFactory = new BenzCarFactory();
// 创建跑车
AbstractSportsCar sportsCar2 = benzCarFactory.createSportsCar();
sportsCar2.drive();
// 创建小轿车
AbstractSedanCar sedanCar2 = benzCarFactory.createSedanCar();
sedanCar2.drive();
}
}
通过使用抽象工厂模式,我们将汽车和工厂的创建过程抽象出来,使得系统更加灵活和可扩展。可以根据需要添加新的汽车类型和工厂类型,而不影响现有代码的结构。
对比和选择
每种工厂设计模式都有其适用的场景。
-
简单工厂模式适合类型个数固定且数量少的情况,因为它易于实现,并且不需要额外的类来处理对象的创建。然而,随着产品数量的增加,简单工厂模式可能会变得难以管理和维护。
-
工厂方法模式适合于产品种类繁多,但是每个种类的产品数量相对较少的情况。它可以将工厂逻辑分散到各个子类中,使得系统在不修改原来代码的情况下可以引进新的产品。
-
抽象工厂模式适合于产品种类繁多,并且每个种类的产品数量也很多的情况。它可以创建一系列相关的对象,而无需指定它们的具体类,从而提供了更高的灵活性。
总的来说,选择哪种工厂设计模式取决于具体的应用场景和需求。在教学中,通过对比和分析这些模式的不同之处,可以帮助学生更好地理解和掌握工厂设计模式。
优缺点
工厂模式的优点包括:
- 封装性:隐藏了对象创建的具体逻辑,使得代码更加简洁、易懂。
- 可扩展性:通过定义抽象工厂或工厂接口,可以方便地添加新的产品类型,而不影响现有系统的正常运行。
- 灵活性:可以在运行时根据不同的条件创建不同类型的对象,提高了系统的灵活性。
- 解耦性:将产品的创建和使用分离,降低了模块之间的耦合度,提高了系统的可维护性和可重用性。
工厂模式的缺点主要有:
- 增加复杂度:引入工厂模式会增加系统的复杂度,需要额外的类或接口来处理对象的创建。
- 效率问题:在一些情况下,可能会因为创建对象的过程而导致一定的性能开销。
- 不完全符合开闭原则:虽然工厂模式在一定程度上支持开闭原则,但在某些变体(如简单工厂模式)中,可能需要修改工厂类来添加新的产品类型,不完全满足开闭原则的要求。
使用场景举例
1. JDBC 获取数据库连接对象
在 JDBC 数据库操作中,可以使用工厂模式创建不同类型的数据库连接对象,根据不同的数据库类型或配置进行连接。
...
private static final String DB_URL = "jdbc:mysql://localhost:3306/db_goods?characterEncoding=utf8";
connection = DriverManager.getConnection(DB_URL,"root","root");
...
这里DriverManager就是一个工厂类,不同的数据库(如 MySQL、Oracle)相当于具体的产品。只需向工厂里传入具体产品的参数,就能用静态方法获取连接到数据库的Connection 对象。
2. Calendar 类获取日历类对象
Calendar calendar = Calendar.getInstance(...);
Calendar 是抽象类,该类的子类有 BuddhistCalendar、JapaneseImperialCalendar、GregorianCalendar、RollingCalendar等。getInstance方法,根据参数获取一个Calendar子类对象,该方法实际将参数传给 createCalendar 方法,createCalendar 在根据参数通过 provider 或 switch 或者 if-else 创建相应的子类对象。

浙公网安备 33010602011771号