Java 工厂设计模式

模式定义

工厂模式是一种创建对象的设计模式,它提供了一种创建对象的接口,使得客户端无需知道具体的创建细节,只需通过该接口就能获取所需的对象。

工厂模式主要解决了以下几个典型问题:

  1. 解耦:将对象的创建过程与使用过程分离,使得两者之间的耦合度降低,提高了系统的灵活性和可维护性。
  2. 灵活性:通过抽象工厂类或工厂方法,可以方便地扩展和添加新的产品对象,而不需要修改现有代码。
  3. 可配置性:可以通过配置文件或其他方式动态地决定创建哪种具体的产品对象,提高了系统的可配置性。
  4. 隐藏实现细节:客户端无需关心对象的具体创建过程和内部结构,只需使用工厂提供的接口,隐藏了实现细节,提高了代码的可读性和可维护性。

例如,在一个汽车制造工厂中,工厂模式可以用于创建不同类型的汽车,而无需让客户直接了解汽车的制造过程。客户只需告诉工厂他们需要的汽车类型,工厂就会创建相应的汽车对象。

模式分类

工厂模式有多种变体,如简单工厂模式、工厂方法模式和抽象工厂模式等,每种变体都有其适用的场景和特点。在实际应用中,需要根据具体的需求选择合适的工厂模式。

简单工厂模式

简单工厂模式也被称为静态工厂方法模式,它通常是一个静态方法,用于根据传入的参数来决定创建哪一个产品的实例。这种模式的优点是客户端可以免除直接创建产品对象的职责,很方便地创建出相应的产品。然而,它的缺点也很明显,例如工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。此外,使用简单工厂模式会增加系统中类的个数,增加系统的复杂度和理解难度。

image

代码示例

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方法来模拟汽车行驶。

通过使用简单工厂模式,我们将汽车的创建过程封装在工厂类中,使得客户端无需关心具体的创建细节,只需提供汽车类型即可获得相应的汽车对象。这样可以提高代码的灵活性和可维护性。

工厂方法模式

工厂方法模式是对简单工厂模式的进一步抽象化,它将工厂逻辑分散到各个子类中,使得系统在不修改原来代码的情况下可以引进新的产品,从而满足开闭原则。这种方式的好处是,当增加新产品时,只需要增加一个新的工厂类,而不需要修改原有的代码。

image

代码示例

// 汽车接口
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方法来模拟汽车行驶。

通过使用工厂方法模式,我们将汽车的创建过程与具体的工厂类解耦,使得系统更加灵活和可扩展。如果需要添加新的汽车类型,只需要创建相应的工厂类和汽车类即可。

抽象工厂模式

抽象工厂模式则是更进一步的抽象化,它允许一个工厂接口创建一系列相关的对象,而无需指定它们的具体类。这种方式的好处是,可以在不修改客户端代码的情况下更换和添加新的具体产品类。

image

代码示例

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. 封装性:隐藏了对象创建的具体逻辑,使得代码更加简洁、易懂。
  2. 可扩展性:通过定义抽象工厂或工厂接口,可以方便地添加新的产品类型,而不影响现有系统的正常运行。
  3. 灵活性:可以在运行时根据不同的条件创建不同类型的对象,提高了系统的灵活性。
  4. 解耦性:将产品的创建和使用分离,降低了模块之间的耦合度,提高了系统的可维护性和可重用性。

工厂模式的缺点主要有:

  1. 增加复杂度:引入工厂模式会增加系统的复杂度,需要额外的类或接口来处理对象的创建。
  2. 效率问题:在一些情况下,可能会因为创建对象的过程而导致一定的性能开销。
  3. 不完全符合开闭原则:虽然工厂模式在一定程度上支持开闭原则,但在某些变体(如简单工厂模式)中,可能需要修改工厂类来添加新的产品类型,不完全满足开闭原则的要求。

使用场景举例

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 创建相应的子类对象。

posted @ 2026-09-29 22:55  Binge-和时间做朋友  阅读(9)  评论(0)    收藏  举报