设计模式-工厂模式

136 阅读7分钟

写在前面

Hello,我是易元,本文主要详细介绍工厂模式的分类、定义及其在实际场景中的使用,若内容有误,请大家留言指正!!

前言

工厂模式(Factory Pattern)是一种创建型设计模式,提供了一种创建对象的方式,而无需指定具体的类。

工厂模式的核心思想是将对象的创建过程进行封装,使得客户端代码与具体类的实现解耦

创建型设计模式共有五种:工厂方法模式抽象工厂模式建造者模式原型模式单例模式

分类

工厂模式主要分为三种:

  1. 简单工厂模式(Simple Factory)
  2. 工厂方法模式(Factory Method)
  3. 抽象工厂模式(Abstract Factory)

简单工厂模式

定义

简单工厂模式通过一个工厂类来创建不同类型的对象,客户端只需要传递参数即可获取所需对象。

工厂方法模式中定义了一个抽象工厂类,并且定义了创建产品对象的公共接口,返回抽象产品对象,抽象工厂子类实现了抽象接口,返回具体产品对象。

使用场景

  1. 对象的创建逻辑简单。
  2. 客户端不需要关心对象的创建细节。

简单示例

产品接口

public interface Product {
    void use();
}

具体产品

public class ProductA implements Product {
    @Override
    public void use() {
        System.out.println("使用产品 A");
    }
}
public class ProductB implements Product {
    @Override
    public void use() {
        System.out.println("使用产品 B");
    }
}

简单工厂类

public class SimpleFactory {
    public static Product createProduct(String type) {
        if ("A".equals(type)) {
            return new ProductA();
        } else if ("B".equals(type)) {
            return new ProductB();
        }
        throw new IllegalArgumentException("未知产品类型!");
    }
}

客户端代码

public class Client {
    public static void main(String[] args) {
        Product productA = SimpleFactory.createProduct("A");
        productA.use(); // 输出: 使用产品 A

        Product productB = SimpleFactory.createProduct("B");
        productB.use(); // 输出: 使用产品 B
    }
}

工厂方法模式

定义

工厂方法模式定义了一个创建对象的接口,但由子类决定实例化具体的类,将对象的创建延迟到子类

将对象的创建延迟到子类解释:工厂方法模式中定义了一个抽象工厂类,并且定义了创建产品对象的公共接口,返回抽象产品对象,抽象工厂子类实现了抽象接口,返回具体产品对象。

使用场景

  1. 对象的创建逻辑复杂,需要根据不同条件创建不同对象。
  2. 需要扩展时,可以通过新增子类来实现。

简单示例

产品接口

public interface Product {
    void use();
}

具体产品

public class ProductA implements Product {
    @Override
    public void use() {
        System.out.println("使用产品 A");
    }
}

public class ProductB implements Product {
    @Override
    public void use() {
        System.out.println("使用产品 B");
    }
}

工厂接口

public interface Factory {
    Product createProduct();
}

具体工厂

public class FactoryA implements Factory {
    @Override
    public Product createProduct() {
        return new ProductA();
    }
}

public class FactoryB implements Factory {
    @Override
    public Product createProduct() {
        return new ProductB();
    }
}

客户端代码

public class Client {
    public static void main(String[] args) {
        Factory factoryA = new FactoryA();
        
        // 由子类创建产品对象
        Product productA = factoryA.createProduct();
        productA.use(); // 输出: 使用产品 A

        Factory factoryB = new FactoryB();
        Product productB = factoryB.createProduct();
        productB.use(); // 输出: 使用产品 B
    }
}

实际使用案例

Spring Framework 中的使用

工厂接口BeanFactory

Spring中最基础的工厂接口,定义了获取Bean的方法。

public interface BeanFactory {
    Object getBean(String name) throws BeansException; // 通过名称获取 Bean
    <T> T getBean(String name, Class<T> requiredType) throws BeansException; // 通过名称和类型获取 Bean
    <T> T getBean(Class<T> requiredType) throws BeansException; // 通过类型获取 Bean
    boolean containsBean(String name)// 检查是否包含指定名称的 Bean
}

具体工厂实现 ClassPathXmlApplicationContext

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyBean myBean = context.getBean(MyBean.class);

产品接口可以理解为Spring管理的Bean的通用接口(自定义创建的接口类),而具体产品则是这些Bean的具体实现(自定义创建的实现类)。

ClassPathXmlApplicationContextApplicationContext的实现类ApplicationContextBeanFactory的子接口,对BeanFactory进行了扩展,例如:国际化、事件发布等

public interface ApplicationContext extends Bean>Factory {
   String getApplicationName()// 获取应用名称
   String getDisplayName()// 获取显示名称
   long getStartupDate()// 获取启动时间
   void publishEvent(ApplicationEvent event); >// 发布事件
}

抽象工厂模式

定义

抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,无需指定它们的具体类。

使用场景

  1. 需要创建一组相关或依赖的对象
  2. 系统中有多个产品族,且客户端只使用其中某一族产品。

简单示例

产品接口

public interface Product {
    void use();
}

具体产品

public class ProductA1 implements Product {
    @Override
    public void use() {
        System.out.println("使用产品 A1");
    }
}

public class ProductA2 implements Product {
    @Override
    public void use() {
        System.out.println("使用产品 A2");
    }
}

public class ProductB1 implements Product {
    @Override
    public void use() {
        System.out.println("使用产品 B1");
    }
}

public class ProductB2 implements Product {
    @Override
    public void use() {
        System.out.println("使用产品 B2");
    }
}

抽象工厂接口

public interface AbstractFactory {
    Product createProduct1();
    Product createProduct2();
}

具体工厂

// A 类型产品
public class FactoryA implements AbstractFactory {
    @Override
    public Product createProduct1() {
        return new ProductA1();
    }

    @Override
    public Product createProduct2() {
        return new ProductA2();
    }
}

// B 类型产品
public class FactoryB implements AbstractFactory {
    @Override
    public Product createProduct1() {
        return new ProductB1();
    }

    @Override
    public Product createProduct2() {
        return new ProductB2();
    }
}

客户端代码

public class Client {
    public static void main(String[] args) {
        AbstractFactory factoryA = new FactoryA();
        Product productA1 = factoryA.createProduct1();
        Product productA2 = factoryA.createProduct2();
        productA1.use(); // 输出: 使用产品 A1
        productA2.use(); // 输出: 使用产品 A2

        AbstractFactory factoryB = new FactoryB();
        Product productB1 = factoryB.createProduct1();
        Product productB2 = factoryB.createProduct2();
        productB1.use(); // 输出: 使用产品 B1
        productB2.use(); // 输出: 使用产品 B2
    }
}

实际使用案例

在 MyBatis 中的使用

抽象工厂SqlSessionFactory

SqlSessionFactory 是 MyBatis 的核心接口,定义了创建 SqlSession 的方法.

public interface SqlSessionFactory {
    SqlSession openSession()// 创建 SqlSession
    SqlSession openSession(boolean autoCommit)// 创建 SqlSession,指定是否自动提交
    SqlSession openSession(Connection connection)// 创建 SqlSession,使用指定的数据库连接
    Configuration getConfiguration()// 获取配置信息
}

具体工厂DefaultSqlSessionFactory

DefaultSqlSessionFactorySqlSessionFactory 的具体实现类,负责创建 SqlSession 对象。

public class DefaultSqlSessionFactory implements SqlSessionFactory {
    private final Configuration configuration;

    public DefaultSqlSessionFactory(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public SqlSession openSession() {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), nullfalse);
    }

    @Override
    public SqlSession openSession(boolean autoCommit) {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
    }

    @Override
    public SqlSession openSession(Connection connection) {
        return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
    }

    @Override
    public Configuration getConfiguration() {
        return configuration;
    }
    
    // 创建 SqlSession 的具体逻辑
    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
      
    }

    // 创建 SqlSession 的具体逻辑
    private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
        
    }
}

抽象产品SqlSession

SqlSession 是 MyBatis 的核心接口,定义了执行 SQL 命令、获取映射器等。

public interface SqlSession extends Closeable {
    <T> selectOne(String statement)// 查询单条记录
    <T> selectOne(String statement, Object parameter)// 查询单条记录,带参数
    <E> List<E> selectList(String statement)// 查询多条记录
    <E> List<E> selectList(String statement, Object parameter)// 查询多条记录,带参数
    int insert(String statement)// 插入记录
    int insert(String statement, Object parameter)// 插入记录,带参数
    int update(String statement)// 更新记录
    int update(String statement, Object parameter)// 更新记录,带参数
    int delete(String statement)// 删除记录
    int delete(String statement, Object parameter)// 删除记录,带参数
    void commit()// 提交事务
    void rollback()// 回滚事务
    <T> getMapper(Class<T> type)// 获取映射器
    Connection getConnection()// 获取数据库连接
}

具体产品DefaultSqlSession

DefaultSqlSessionSqlSession 的具体实现类,负责执行 SQL 命令、管理事务等。

public class DefaultSqlSession implements SqlSession {
    private final Configuration configuration;
    private final Executor executor;
    private final boolean autoCommit;

    public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
        this.configuration = configuration;
        this.executor = executor;
        this.autoCommit = autoCommit;
    }

    @Override
    public <T> T selectOne(String statement) {
        return selectOne(statement, null);
    }

    @Override
    public <T> T selectOne(String statement, Object parameter) {
        List<T> list = selectList(statement, parameter);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
            return null;
        }
    }

    @Override
    public <E> List<E> selectList(String statement) {
        return selectList(statement, null);
    }

    @Override
    public <E> List<E> selectList(String statement, Object parameter) {
        try {
            MappedStatement ms = configuration.getMappedStatement(statement);
            return executor.query(ms, parameter, RowBounds.DEFAULTExecutor.NO_RESULT_HANDLER);
        } catch (Exception e) {
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
        } finally {
            ErrorContext.instance().reset();
        }
    }
 ...
}

长话短说

  1. 简单工厂模式:一个工厂类负责创建所有产品。
  2. 工厂方法模式:每个产品对应一个工厂类。
  3. 抽象工厂模式:每个工厂类负责创建一组相关产品。

何时可以使用?

  1. 对象的创建逻辑复杂
  • 若对象的创建过程涉及到复杂的初始化逻辑(如 配置加载,依赖注入等等),可以使用工厂模式将创建的逻辑封装起来以便后期维护。
  1. 需要支持多种实现
  • 若系统需要支持多种实现(如多种支付方式、多数据库类型等),可以使用工厂模式动态的创建对象。
  1. 需要解耦客户端与具体实现
  • 若客户端代码需要与具体实现进行解耦,可以使用工厂模式隐藏具体实现细节。
  1. 需要集中管理对象的创建
  • 若对象的创建逻辑分散在多个地方,可以使用工厂模式将创建的逻辑集中管理。
  1. 需要动态扩展
  • 若在开发中预见可能存在新的产品类型,可以预先使用工厂模式以便当新的产品出现时动态的扩展。

如何使用?四步走!

  1. 定义产品接口
  • 定义产品的通用接口或抽象类。
  1. 实现具体产品
  • 实现产品接口,定义具体产品的行为。
  1. 定义工厂接口
  • 定义工厂接口,在其中声明产品的创建方法。
  1. 实现具体工厂
  • 实现工厂接口,创建具体产品。