牧瀬クリスだ头像
三种工厂模式详解:从简单到抽象的进阶之路封面图

三种工厂模式详解:从简单到抽象的进阶之路

引言

先看一段很常见的代码:

java

public class OrderService {
    public void pay(String payType) {
        if ("alipay".equals(payType)) {
            new Alipay().pay();
        } else if ("wechat".equals(payType)) {
            new WechatPay().pay();
        } else if ("unionpay".equals(payType)) {
            new UnionPay().pay();
        }
        // 以后每加一种支付方式,都要回来改这个 if-else……
    }
}

这种写法的毛病很明显:调用方既要知道"有哪些支付方式",又要负责"怎么把它们 new 出来",而且每新增一种支付方式,就得回来改这段判断逻辑,违反了开闭原则。

工厂模式(Factory Pattern)就是用来把"对象的创建过程"从业务代码里抽离出来、集中封装到专门的地方。它属于创建型设计模式。这篇文章我会从最简单的简单工厂讲起,一路讲到工厂方法、抽象工厂,并说清楚三者的区别和适用场景。

一、为什么需要工厂模式

工厂模式解决的核心问题是:解耦"对象的创建"和"对象的使用"​。

  • 对调用方来说,我不关心对象怎么 new 出来的、具体是哪个实现类,我只管拿到一个能用的对象。
  • 对代码维护来说,新增产品时,只需改工厂一处(或新增一个工厂类),而不必改动所有调用方。

一句话:把创建逻辑集中管理,让变化只发生在一个地方。​

二、简单工厂模式(Simple Factory)

简单工厂严格来说不算 GoF 23 种设计模式之一,但它是工厂方法的前身,最常用也最好理解。

2.1 定义产品接口

java

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

public class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个正方形");
    }
}

2.2 创建工厂

java

public class ShapeFactory {
    public static Shape getShape(String type) {
        if ("circle".equalsIgnoreCase(type)) {
            return new Circle();
        } else if ("square".equalsIgnoreCase(type)) {
            return new Square();
        }
        return null;
    }
}

2.3 使用

java

public class Main {
    public static void main(String[] args) {
        Shape circle = ShapeFactory.getShape("circle");
        circle.draw(); // 画一个圆形

        Shape square = ShapeFactory.getShape("square");
        square.draw(); // 画一个正方形
    }
}
  • 优点:调用方只依赖工厂和接口,不再直接 new 具体类。
  • 缺点:每新增一种产品,都要改工厂里的 if-else,仍然违背开闭原则。所以它适合"产品种类很少且稳定"的场景。

三、工厂方法模式(Factory Method)

工厂方法把"一个万能工厂"拆成了"每个产品对应一个工厂",新增产品时不再改原有工厂,而是新增一个工厂类,符合开闭原则。

3.1 定义抽象工厂

java

public interface ShapeFactory {
    Shape createShape();
}

3.2 每个产品一个工厂

java

public class CircleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Circle();
    }
}

public class SquareFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Square();
    }
}

3.3 使用

java

public class Main {
    public static void main(String[] args) {
        ShapeFactory circleFactory = new CircleFactory();
        Shape circle = circleFactory.createShape();
        circle.draw(); // 画一个圆形

        ShapeFactory squareFactory = new SquareFactory();
        Shape square = squareFactory.createShape();
        square.draw(); // 画一个正方形
    }
}
  • 优点:新增产品只需新增一个"产品类 + 对应的工厂类",不动原有代码,符合开闭原则。
  • 缺点:类的数量会成倍增加,产品多了以后代码会比较繁琐。

四、抽象工厂模式(Abstract Factory)

抽象工厂用于创建"一族相关或相互依赖的对象",而不只是单一对象。典型例子是跨平台的 UI 组件库:一个抽象工厂负责生产一套匹配的按钮、文本框等。

4.1 定义一族产品

java

// 产品一:按钮
public interface Button {
    void click();
}

// 产品二:文本框
public interface TextField {
    void input();
}

4.2 定义抽象工厂(生产一族产品)

java

public interface UIFactory {
    Button createButton();
    TextField createTextField();
}

4.3 两套具体工厂 + 对应产品

java

// Windows 风格
public class WindowsButton implements Button {
    @Override public void click() { System.out.println("Windows 按钮被点击"); }
}
public class WindowsTextField implements TextField {
    @Override public void input() { System.out.println("Windows 文本框输入"); }
}
public class WindowsFactory implements UIFactory {
    @Override public Button createButton() { return new WindowsButton(); }
    @Override public TextField createTextField() { return new WindowsTextField(); }
}

// Mac 风格
public class MacButton implements Button {
    @Override public void click() { System.out.println("Mac 按钮被点击"); }
}
public class MacTextField implements TextField {
    @Override public void input() { System.out.println("Mac 文本框输入"); }
}
public class MacFactory implements UIFactory {
    @Override public Button createButton() { return new MacButton(); }
    @Override public TextField createTextField() { return new MacTextField(); }
}

4.4 使用

java

public class Main {
    public static void main(String[] args) {
        // 假设通过配置决定用哪套 UI
        UIFactory factory = new WindowsFactory();

        Button button = factory.createButton();
        TextField textField = factory.createTextField();
        button.click();      // Windows 按钮被点击
        textField.input();   // Windows 文本框输入
    }
}

关键点:抽象工厂保证你拿到的是"同一族"产品——用 WindowsFactory 就绝不会拿到 MacButton,从源头上避免了风格混搭。缺点是一旦要新增一个产品(比如加个"下拉框"),所有工厂类都要改。

五、三种工厂对比

模式创建对象数扩展方式适用场景
简单工厂单一对象改工厂的 if-else(违背开闭)产品种类少且稳定
工厂方法单一对象新增工厂类(符合开闭)产品种类多、会频繁新增
抽象工厂一族对象新增工厂族需要成套、成族地生产产品

记忆口诀:简单工厂是"一个工厂生产多种产品";工厂方法是"一种产品一个工厂";抽象工厂是"一个工厂生产一族产品"。

六、实际应用:Spring 中的工厂

Spring 本身就大量运用了工厂思想:

  • BeanFactory:Spring 容器的核心接口,负责创建、管理所有 Bean,是最典型的工厂。
  • FactoryBean 接口:一个 Bean 如果实现了 FactoryBean<T>,Spring 会把它当作"工厂",通过 getObject() 返回真正的对象,常用于创建一些构造复杂的对象。

java

@Component
public class MyFactoryBean implements FactoryBean<UserService> {
    @Override
    public UserService getObject() throws Exception {
        // 这里可以做复杂的初始化逻辑
        return new UserService();
    }

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

再比如支付场景(引言里的例子),用工厂方法重构后就清爽多了:

java

public interface PayService {
    void pay();
}
public class AlipayService implements PayService {
    @Override public void pay() { System.out.println("支付宝支付"); }
}
public class WechatPayService implements PayService {
    @Override public void pay() { System.out.println("微信支付"); }
}

// 工厂 + Spring 注入,自动收集所有实现
@Component
public class PayFactory {
    private final Map<String, PayService> payMap = new HashMap<>();

    public PayFactory(List<PayService> payServices) {
        // 这里配合自定义注解,把类型名和实现对应起来
    }

    public PayService get(String type) {
        return payMap.get(type);
    }
}

这样新增支付方式时,只需新增一个 PayService 实现类,业务代码的 if-else 就能逐步被工厂替代。

总结

工厂模式的核心价值是解耦创建与使用,把变化收敛到一处:

  1. 简单工厂:一个工厂集中创建多种产品,代码最直观,但新增产品要改工厂,适合产品少的场景。
  2. 工厂方法:一个产品对应一个工厂,新增产品只加类不改旧代码,符合开闭原则,是扩展性最平衡的选择。
  3. 抽象工厂:生产"一族"相关产品,适合需要成套搭配、保证同族的场景(如跨平台 UI)。
  4. Spring 的 BeanFactory、FactoryBean 都是工厂思想的落地,日常开发中"支付方式、短信渠道、存储引擎"等场景都能用工厂来消除大段 if-else。

一句话总结:当你发现代码里有一大坨 if-else / switch 在负责 new 对象时,就该考虑用工厂模式把它抽出来了。

 

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2501_93705143/article/details/168101575

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--