工厂方法模式

37 阅读6分钟

工厂方法模式(Factory Method Pattern)是一种创建型设计模式,用于定义一个创建对象的接口,让子类决定实例化哪一个类。通过使用工厂方法模式,可以将对象的创建过程延迟到子类中,从而提高代码的灵活性和可扩展性。 工厂方法模式的核心要点是通过定义一个用于创建对象的接口,将具体类的实例化延迟到子类中,以实现对象创建的灵活性和可扩展性。以下是工厂方法模式的一些关键要点:

1. 接口与实现分离

工厂方法模式将对象的创建与具体类的实现分离。客户端代码通过调用工厂方法获取对象实例,而不需要了解具体类的创建细节。

2. 抽象工厂

定义一个抽象工厂接口或抽象类,包含一个或多个工厂方法,用于创建产品对象。

3. 具体工厂

具体工厂类实现抽象工厂接口或继承抽象工厂类,提供具体产品对象的创建逻辑。

4. 产品接口

定义产品接口或抽象类,具体产品类实现该接口或继承该抽象类。

5. 延迟到子类

通过将对象的实例化延迟到子类,工厂方法模式使得添加新的产品类型变得更加容易,而无需修改现有的代码结构。

6. 多态性

通过使用多态性,工厂方法模式允许客户端代码在运行时根据需要创建不同类型的对象。

7. 优点

  • 松耦合:客户端代码与具体类解耦,增强了代码的灵活性和可维护性。
  • 可扩展性:容易添加新的产品类型,无需修改现有代码。
  • 遵循设计原则:符合开闭原则(Open/Closed Principle),对扩展开放,对修改关闭。

8. 缺点

  • 复杂性:引入了额外的类和接口,增加了系统的复杂性。
  • 额外工作量:需要创建多个子类,可能增加开发工作量。

示例

下面是一个简单的例子,展示如何使用工厂方法模式:

  1. 定义一个抽象的产品接口:
public interface Product {
    void use();
}
  1. 创建具体的产品类,实现产品接口:
public class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA");
    }
}

public class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductB");
    }
}
  1. 定义一个抽象的工厂类,包含一个抽象的工厂方法:
public abstract class Factory {
    public abstract Product createProduct();

    public void doSomething() {
        Product product = createProduct();
        product.use();
    }
}
  1. 创建具体的工厂类,继承抽象工厂类,并实现工厂方法:
public class ConcreteFactoryA extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

public class ConcreteFactoryB extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}
  1. 使用工厂类创建具体的产品:
public class Client {
    public static void main(String[] args) {
        Factory factoryA = new ConcreteFactoryA();
        factoryA.doSomething();

        Factory factoryB = new ConcreteFactoryB();
        factoryB.doSomething();
    }
}

解释

  • Product接口:定义了产品的抽象类型。
  • ConcreteProductA和ConcreteProductB:具体产品类,实现了Product接口。
  • Factory类:抽象工厂类,定义了抽象的工厂方法createProduct(),用于创建产品对象。
  • ConcreteFactoryA和ConcreteFactoryB:具体工厂类,实现了抽象的工厂方法createProduct(),用于创建具体的产品对象。

工厂方法模式的核心在于将对象的创建过程封装在工厂类中,客户端只需与工厂类交互,而不需要关心具体产品的创建细节。这提高了代码的灵活性和可扩展性,便于添加新的产品类型。

在Spring框架中,工厂方法模式被广泛应用于各种组件和服务的创建与管理。Spring的IOC(Inversion of Control,控制反转)容器使用工厂方法模式来实例化和配置Bean。下面是工厂方法模式在Spring中的一些具体实现:

1. 使用工厂Bean

Spring提供了FactoryBean接口,允许我们自定义Bean的实例化逻辑。以下是一个示例:

  1. 定义一个Bean类
public class MyBean {
    public void doSomething() {
        System.out.println("Doing something in MyBean");
    }
}
  1. 实现FactoryBean接口
import org.springframework.beans.factory.FactoryBean;

public class MyBeanFactory implements FactoryBean<MyBean> {
    @Override
    public MyBean getObject() throws Exception {
        return new MyBean(); // 自定义的实例化逻辑
    }

    @Override
    public Class<?> getObjectType() {
        return MyBean.class;
    }

    @Override
    public boolean isSingleton() {
        return true; // 返回true表示是单例模式
    }
}
  1. 在Spring配置文件中配置FactoryBean
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myBean" class="com.example.MyBeanFactory"/>

</beans>

2. 静态工厂方法

Spring还支持通过静态工厂方法来创建Bean实例。以下是一个示例:

  1. 定义一个静态工厂类
public class StaticFactory {
    public static MyBean createInstance() {
        return new MyBean(); // 静态工厂方法
    }
}
  1. 在Spring配置文件中配置静态工厂方法
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myBean" class="com.example.StaticFactory" factory-method="createInstance"/>

</beans>

3. 实例工厂方法

实例工厂方法类似于静态工厂方法,但使用实例来创建Bean。以下是一个示例:

  1. 定义一个实例工厂类
public class InstanceFactory {
    public MyBean createInstance() {
        return new MyBean(); // 实例工厂方法
    }
}
  1. 在Spring配置文件中配置实例工厂方法
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 定义工厂实例 -->
    <bean id="factory" class="com.example.InstanceFactory"/>

    <!-- 使用工厂实例创建Bean -->
    <bean id="myBean" factory-bean="factory" factory-method="createInstance"/>

</beans>

在这些示例中,我们可以看到Spring是如何利用工厂方法模式来创建和管理Bean实例的。这种设计模式极大地提高了Spring框架的灵活性和可扩展性。

工厂方法模式在Java类库中有许多实际应用。以下是一些著名的使用工厂方法模式的Java类库和框架:

1. java.util.Calendar

Calendar类使用了工厂方法模式来创建实例。我们不能直接实例化Calendar,而是通过工厂方法getInstance()来获取实例。

import java.util.Calendar;

public class CalendarExample {
    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        System.out.println("Current time: " + calendar.getTime());
    }
}

2. java.sql.DriverManager

DriverManager类使用了工厂方法模式来创建数据库连接。通过静态方法getConnection()来获取数据库连接实例。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DriverManagerExample {
    public static void main(String[] args) {
        try {
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
            System.out.println("Connection established: " + connection);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

3. java.util.ResourceBundle

ResourceBundle类使用工厂方法模式来加载资源包。通过静态方法getBundle()来获取资源包实例。

import java.util.Locale;
import java.util.ResourceBundle;

public class ResourceBundleExample {
    public static void main(String[] args) {
        ResourceBundle bundle = ResourceBundle.getBundle("MyResources", Locale.US);
        System.out.println("Hello message: " + bundle.getString("hello"));
    }
}

4. java.nio.file.Files

Files类使用了工厂方法模式来创建文件和目录。通过静态方法如createFile()createDirectory()来创建文件和目录实例。

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;

public class FilesExample {
    public static void main(String[] args) {
        Path path = Paths.get("example.txt");
        try {
            Files.createFile(path);
            System.out.println("File created: " + path);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

5. javax.xml.parsers.DocumentBuilderFactory

DocumentBuilderFactory使用工厂方法模式来创建DocumentBuilder实例。

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

public class DocumentBuilderFactoryExample {
    public static void main(String[] args) {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            System.out.println("DocumentBuilder created: " + builder);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
    }
}