1. 工厂模式概述
工厂模式是创建型设计模式中最基础也最常用的模式之一,它通过将对象的创建过程封装到一个专门的类中,实现了对象创建与使用的解耦。在实际开发中,我们经常会遇到需要根据不同条件创建不同类型对象的场景,如果直接在业务代码中通过new关键字创建对象,会导致代码高度耦合且难以维护。
工厂模式的核心思想可以类比现实生活中的汽车制造厂。当我们需要一辆汽车时,不需要知道发动机如何组装、车身如何焊接,只需要告诉工厂"我需要一辆SUV"或"我需要一辆轿车",工厂就会返回符合要求的汽车产品。这种"要什么给什么"的抽象正是工厂模式的精髓所在。
2. 工厂模式的三种实现形式
2.1 简单工厂模式
简单工厂模式是最基础的实现形式,它通过一个工厂类中的静态方法来创建不同产品。虽然严格来说它并不属于GoF 23种设计模式之一,但理解它有助于我们掌握更复杂的工厂模式。
java复制public class SimplePizzaFactory {
public static Pizza createPizza(String type) {
Pizza pizza = null;
switch(type) {
case "cheese":
pizza = new CheesePizza();
break;
case "pepperoni":
pizza = new PepperoniPizza();
break;
case "veggie":
pizza = new VeggiePizza();
break;
}
return pizza;
}
}
注意:简单工厂模式的缺点是当需要新增产品类型时,必须修改工厂类的代码,这违反了开闭原则。因此它更适合产品类型较少且不频繁变化的场景。
2.2 工厂方法模式
工厂方法模式通过引入抽象工厂接口,将具体产品的创建延迟到子类中实现,完美解决了简单工厂模式违反开闭原则的问题。
java复制// 抽象工厂接口
public interface PizzaFactory {
Pizza createPizza();
}
// 具体工厂类
public class NYCheesePizzaFactory implements PizzaFactory {
@Override
public Pizza createPizza() {
return new NYStyleCheesePizza();
}
}
public class ChicagoCheesePizzaFactory implements PizzaFactory {
@Override
public Pizza createPizza() {
return new ChicagoStyleCheesePizza();
}
}
工厂方法模式的UML类图通常包含以下角色:
- Product(抽象产品)
- ConcreteProduct(具体产品)
- Creator(抽象工厂)
- ConcreteCreator(具体工厂)
2.3 抽象工厂模式
抽象工厂模式是工厂方法模式的升级版,它能够创建多个产品族中的对象。比如在GUI开发中,我们可能需要创建一整套风格一致的控件(按钮、文本框、下拉框等)。
java复制// 抽象工厂接口
public interface GUIFactory {
Button createButton();
TextField createTextField();
ComboBox createComboBox();
}
// Windows风格工厂
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextField createTextField() {
return new WindowsTextField();
}
@Override
public ComboBox createComboBox() {
return new WindowsComboBox();
}
}
// Mac风格工厂
public class MacFactory implements GUIFactory {
// 类似实现Mac风格的控件创建
}
3. 工厂模式的核心应用场景
3.1 框架中的对象创建
大多数开发框架都大量使用工厂模式。例如Spring框架中的BeanFactory就是典型的抽象工厂实现,它负责创建和管理应用中的所有Bean对象。
java复制ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean(UserService.class);
3.2 数据库访问层设计
在数据库访问层中,我们通常需要根据不同数据库类型创建不同的连接对象。使用工厂模式可以优雅地实现这一需求。
java复制public interface ConnectionFactory {
Connection createConnection();
}
public class MySQLConnectionFactory implements ConnectionFactory {
@Override
public Connection createConnection() {
// 创建MySQL连接的具体实现
}
}
public class OracleConnectionFactory implements ConnectionFactory {
@Override
public Connection createConnection() {
// 创建Oracle连接的具体实现
}
}
3.3 跨平台UI开发
在需要支持多平台的UI框架中,抽象工厂模式可以确保为每个平台创建风格一致的UI组件。Flutter框架的底层渲染引擎就采用了类似的模式。
4. 工厂模式的进阶应用技巧
4.1 结合反射机制实现动态工厂
通过Java反射机制,我们可以实现更灵活的工厂模式,无需在代码中硬编码具体产品类。
java复制public class DynamicFactory {
public static <T> T create(Class<T> clazz) {
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("创建对象失败", e);
}
}
}
// 使用示例
Product product = DynamicFactory.create(ConcreteProduct.class);
4.2 使用枚举实现单例工厂
对于只需要单一实例的工厂,可以结合枚举类型实现线程安全的单例工厂。
java复制public enum SingletonFactory {
INSTANCE;
public Product createProduct() {
return new ConcreteProduct();
}
}
// 使用示例
Product product = SingletonFactory.INSTANCE.createProduct();
4.3 工厂模式与依赖注入的结合
在现代框架中,工厂模式常与依赖注入(DI)结合使用。通过配置元数据声明对象的创建方式,由容器负责实例化和管理对象生命周期。
java复制@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserServiceImpl();
}
}
5. 工厂模式的性能优化策略
5.1 对象池技术
对于创建成本较高的对象,可以在工厂中引入对象池技术,避免频繁创建和销毁对象。
java复制public class ConnectionPoolFactory {
private static final int POOL_SIZE = 10;
private static final List<Connection> pool = new ArrayList<>();
static {
for (int i = 0; i < POOL_SIZE; i++) {
pool.add(createNewConnection());
}
}
public static Connection getConnection() {
if (pool.isEmpty()) {
return createNewConnection();
}
return pool.remove(0);
}
public static void releaseConnection(Connection conn) {
if (pool.size() < POOL_SIZE) {
pool.add(conn);
} else {
closeConnection(conn);
}
}
}
5.2 缓存机制
对于不变的对象,工厂可以实现缓存机制,避免重复创建相同的对象。
java复制public class ProductFactory {
private static final Map<String, Product> cache = new ConcurrentHashMap<>();
public static Product getProduct(String key) {
return cache.computeIfAbsent(key, k -> {
// 根据key创建对应的产品
return createProductByKey(k);
});
}
}
5.3 延迟初始化
对于不一定会用到的重量级对象,可以采用延迟初始化策略,在第一次使用时才创建对象。
java复制public class LazyFactory {
private static volatile HeavyObject instance;
public static HeavyObject getInstance() {
if (instance == null) {
synchronized (LazyFactory.class) {
if (instance == null) {
instance = new HeavyObject();
}
}
}
return instance;
}
}
6. 工厂模式的常见误用与规避
6.1 过度设计问题
在简单场景中使用工厂模式可能会导致过度设计。如果对象的创建逻辑非常简单,且不太可能变化,直接使用new关键字可能更合适。
反例:
java复制// 过度使用工厂模式
public class SimpleObjectFactory {
public static SimpleObject create() {
return new SimpleObject();
}
}
6.2 违反单一职责原则
当工厂类承担过多职责时,会导致代码难以维护。一个好的工厂类应该只负责创建一种类型的对象或其系列对象。
反例:
java复制// 违反单一职责的工厂
public class BadFactory {
public Product createProduct() { /*...*/ }
public User createUser() { /*...*/ }
public Order createOrder() { /*...*/ }
}
6.3 忽略异常处理
工厂方法中如果没有妥善处理对象创建可能抛出的异常,会导致问题被隐藏。
正确做法:
java复制public class SafeFactory {
public Product createProduct() {
try {
return new ComplexProduct();
} catch (ProductCreationException e) {
log.error("创建产品失败", e);
throw new BusinessException("产品创建失败,请稍后重试");
}
}
}
7. 工厂模式在现代框架中的演变
7.1 Spring中的工厂Bean
Spring框架提供了FactoryBean接口,允许开发者自定义复杂的对象创建逻辑。
java复制public class MyFactoryBean implements FactoryBean<MyObject> {
@Override
public MyObject getObject() throws Exception {
// 复杂的对象创建逻辑
return new MyObject();
}
@Override
public Class<?> getObjectType() {
return MyObject.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
7.2 Java 8中的Supplier函数式接口
Java 8引入的函数式编程特性为工厂模式提供了新的实现方式。
java复制public class SupplierFactory {
private static final Map<String, Supplier<Product>> suppliers = new HashMap<>();
static {
suppliers.put("simple", SimpleProduct::new);
suppliers.put("advanced", AdvancedProduct::new);
}
public static Product createProduct(String type) {
Supplier<Product> supplier = suppliers.get(type);
if (supplier == null) {
throw new IllegalArgumentException("未知的产品类型");
}
return supplier.get();
}
}
7.3 响应式编程中的工厂模式
在响应式编程中,工厂模式常用于创建Publisher或Processor等响应式组件。
java复制public class ReactiveFactory {
public static Flux<Integer> createNumberFlux(int count) {
return Flux.range(1, count)
.delayElements(Duration.ofMillis(100));
}
public static Mono<String> createGreetingMono(String name) {
return Mono.fromSupplier(() -> "Hello, " + name);
}
}
8. 工厂模式的测试策略
8.1 工厂方法的单元测试
测试工厂方法时,需要验证它能否正确创建预期的对象实例。
java复制@Test
void testCreateProduct() {
ProductFactory factory = new ConcreteProductFactory();
Product product = factory.createProduct();
assertNotNull(product);
assertTrue(product instanceof ConcreteProduct);
assertEquals("expectedName", product.getName());
}
8.2 模拟工厂依赖
当测试依赖于工厂的代码时,可以使用Mock框架模拟工厂行为。
java复制@Test
void testServiceWithMockFactory() {
ProductFactory mockFactory = mock(ProductFactory.class);
when(mockFactory.createProduct()).thenReturn(new TestProduct());
ProductService service = new ProductService(mockFactory);
String result = service.processProduct();
assertEquals("TestResult", result);
}
8.3 工厂性能测试
对于实现对象池或缓存的工厂,需要进行性能测试以确保其优化效果。
java复制@Test
void testPoolPerformance() {
long start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
Connection conn = ConnectionPoolFactory.getConnection();
// 使用连接
ConnectionPoolFactory.releaseConnection(conn);
}
long duration = System.currentTimeMillis() - start;
assertTrue(duration < 1000, "获取1000次连接应在1秒内完成");
}
9. 工厂模式与其他模式的协同
9.1 工厂模式与单例模式
工厂类本身通常实现为单例,以确保全局只有一个工厂实例。
java复制public class SingletonFactory {
private static final SingletonFactory INSTANCE = new SingletonFactory();
private SingletonFactory() {}
public static SingletonFactory getInstance() {
return INSTANCE;
}
public Product createProduct() {
return new ConcreteProduct();
}
}
9.2 工厂模式与原型模式
工厂可以使用原型模式通过克隆现有对象来创建新对象,避免昂贵的初始化过程。
java复制public class PrototypeFactory {
private static final Map<String, Product> prototypes = new HashMap<>();
static {
prototypes.put("default", new DefaultProduct());
prototypes.put("advanced", new AdvancedProduct());
}
public static Product createProduct(String type) {
Product prototype = prototypes.get(type);
if (prototype == null) {
throw new IllegalArgumentException("未知的产品类型");
}
return prototype.clone();
}
}
9.3 工厂模式与装饰器模式
工厂可以返回经过装饰的原始对象,为客户端提供增强功能。
java复制public class DecoratedProductFactory {
public Product createProduct() {
Product product = new BasicProduct();
return new LoggingDecorator(
new MetricsDecorator(
new CachingDecorator(product)));
}
}
10. 工厂模式的实战案例
10.1 电商系统中的折扣策略工厂
在电商系统中,不同的促销活动需要应用不同的折扣策略。使用工厂模式可以灵活地创建各种折扣策略。
java复制public interface DiscountStrategy {
BigDecimal applyDiscount(Order order);
}
public class DiscountStrategyFactory {
public static DiscountStrategy createStrategy(String promoType) {
switch (promoType) {
case "FESTIVAL":
return new FestivalDiscount();
case "VIP":
return new VIPDiscount();
case "COUPON":
return new CouponDiscount();
default:
return new NoDiscount();
}
}
}
10.2 游戏开发中的角色工厂
在游戏开发中,需要根据角色类型创建不同的角色对象。工厂模式可以很好地管理这种创建逻辑。
java复制public abstract class GameCharacter {
public abstract void render();
public abstract void update();
}
public class CharacterFactory {
public static GameCharacter createCharacter(String type) {
switch (type) {
case "warrior":
return new Warrior();
case "mage":
return new Mage();
case "archer":
return new Archer();
default:
throw new IllegalArgumentException("未知的角色类型");
}
}
}
10.3 微服务架构中的客户端工厂
在微服务架构中,为不同服务创建API客户端时,可以使用工厂模式统一管理客户端的创建过程。
java复制public interface ServiceClient {
String callService(Request request);
}
public class ClientFactory {
private static final Map<String, ServiceClient> clients = new ConcurrentHashMap<>();
public static ServiceClient getClient(String serviceName) {
return clients.computeIfAbsent(serviceName, name -> {
// 根据服务名创建对应的客户端
return createClientForService(name);
});
}
}
11. 工厂模式的替代方案
11.1 依赖注入容器
现代开发中,依赖注入容器(如Spring IOC)可以替代大部分工厂模式的使用场景。
java复制@Service
public class ProductService {
private final ProductRepository repository;
@Autowired
public ProductService(ProductRepository repository) {
this.repository = repository;
}
}
11.2 ServiceLoader机制
Java的ServiceLoader提供了一种发现和加载实现给定接口的服务提供者的方式,可以看作是一种内置的工厂模式。
java复制// 在META-INF/services中声明实现类
ServiceLoader<Encoder> loader = ServiceLoader.load(Encoder.class);
for (Encoder encoder : loader) {
// 使用找到的编码器
}
11.3 Builder模式
对于创建过程复杂的对象,Builder模式可能是比工厂模式更好的选择。
java复制HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(3))
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
12. 工厂模式的未来发展趋势
随着编程语言和框架的发展,工厂模式也在不断演进。函数式编程的兴起使得工厂方法可以通过函数引用来实现,云原生架构中的Operator模式本质上也是一种工厂模式的应用。在未来,工厂模式可能会与以下技术更深度地结合:
- 云原生架构:Kubernetes中的CRD(Custom Resource Definition)和Operator模式
- Serverless计算:函数即服务(FaaS)中的函数工厂
- AI模型部署:模型工厂自动创建和配置推理服务
- 区块链智能合约:合约工厂部署和管理合约实例
工厂模式作为最基础的设计模式之一,其核心思想——将对象的创建与使用分离——永远不会过时,但实现形式会随着技术发展而不断革新。