工廠模式是創建型模式基石,核心目的是封裝對象創建邏輯、解耦調用者與具體實現類。本文從最基礎的簡單工廠講起,層層遞進至工廠方法、抽象工廠,並給出 Spring 源碼級應用場景、選型決策樹與最佳實踐。
Shape)Circle, Rectangle)一個類根據傳入參數決定創建哪種產品實例。違反開閉原則 (新增產品需修改工廠代碼),但結構簡單,適用於產品類型固定、創建邏輯不複雜場景。
// 1. 產品接口
public interface Shape {
void draw();
double area();
}
// 2. 具體產品
public class Circle implements Shape {
private final double radius;
public Circle(double radius) { this.radius = radius; }
@Override public void draw() { System.out.println("繪製圓形 r=" + radius); }
@Override public double area() { return Math.PI * radius * radius; }
}
public class Rectangle implements Shape {
private final double width, height;
public Rectangle(double w, double h) { this.width = w; this.height = h; }
@Override public void draw() { System.out.println("繪製矩形 " + width + "x" + height); }
@Override public double area() { return width * height; }
}
public class Square implements Shape {
private final double side;
public Square(double side) { this.side = side; }
@Override public void draw() { System.out.println("繪製正方形 " + side); }
@Override public double area() { return side * side; }
}
// 3. 簡單工廠 (靜態方法版)
public final class ShapeFactory {
private ShapeFactory() {} // 防止實例化
public static Shape createShape(String type, double... params) {
return switch (type.toLowerCase()) {
case "circle" -> new Circle(params[0]);
case "rectangle" -> new Rectangle(params[0], params[1]);
case "square" -> new Square(params[0]);
default -> throw new IllegalArgumentException("未知形狀: " + type);
};
}
}
// 4. 客戶端調用
public class Client {
public static void main(String[] args) {
Shape c = ShapeFactory.createShape("circle", 5.0);
c.draw(); // 繪製圓形 r=5.0
System.out.println("面積: " + c.area());
}
}
定義創建對象的接口,由子類決定實例化哪個具體類。將創建責任下放到子類,新增產品只需新增工廠子類,**不修改現有代碼**。
// 1. 抽象工廠接口
public interface ShapeFactory {
Shape createShape(double... params);
}
// 2. 具體工廠 (每種產品一個工廠類)
public class CircleFactory implements ShapeFactory {
@Override public Shape createShape(double... params) {
return new Circle(params[0]);
}
}
public class RectangleFactory implements ShapeFactory {
@Override public Shape createShape(double... params) {
return new Rectangle(params[0], params[1]);
}
}
// 3. 客戶端依賴抽象工廠
public class DrawingApp {
private final ShapeFactory factory;
public DrawingApp(ShapeFactory factory) { this.factory = factory; }
public void drawShape(double... params) {
Shape shape = factory.createShape(params);
shape.draw();
}
}
// 4. 使用 (可配合 DI 容器注入具體工廠)
public class Main {
public static void main(String[] args) {
DrawingApp app = new DrawingApp(new CircleFactory());
app.drawShape(10.0);
}
}
// FactoryBean 接口:Spring 內建工廠方法模式
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
// 典型實現:SqlSessionFactoryBean (MyBatis)、LocalContainerEntityManagerFactoryBean (JPA)
// 客戶端注入 SqlSessionFactory,完全感知不到創建邏輯
提供一個接口,用於創建相關或依賴對象的家族,而無需指定具體類。適用於系統有多個產品族、客戶端只使用某一族產品的場景。
// 1. 產品族接口
public interface Button { void render(); void onClick(Runnable action); }
public interface Checkbox { void render(); void toggle(); }
public interface ScrollBar { void render(); }
// 2. Windows 族具體產品
public class WindowsButton implements Button { /* ... */ }
public class WindowsCheckbox implements Checkbox { /* ... */ }
public class WindowsScrollBar implements ScrollBar { /* ... */ }
// 3. Mac 族具體產品
public class MacButton implements Button { /* ... */ }
public class MacCheckbox implements Checkbox { /* ... */ }
public class MacScrollBar implements ScrollBar { /* ... */ }
// 4. 抽象工廠:定義創建整族產品的方法群
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
ScrollBar createScrollBar();
}
// 5. 具體工廠:每族一個
public class WindowsFactory implements GUIFactory {
@Override public Button createButton() { return new WindowsButton(); }
@Override public Checkbox createCheckbox() { return new WindowsCheckbox(); }
@Override public ScrollBar createScrollBar() { return new WindowsScrollBar(); }
}
public class MacFactory implements GUIFactory {
@Override public Button createButton() { return new MacButton(); }
@Override public Checkbox createCheckbox() { return new MacCheckbox(); }
@Override public ScrollBar createScrollBar() { return new MacScrollBar(); }
}
// 6. 客戶端:僅依賴抽象工廠與產品接口
public class Application {
private final Button button;
private final Checkbox checkbox;
public Application(GUIFactory factory) {
button = factory.createButton();
checkbox = factory.createCheckbox();
}
public void renderUI() {
button.render();
checkbox.render();
}
}
// 7. 運行時動態切換族
public class Main {
public static void main(String[] args) {
String os = System.getProperty("os.name").toLowerCase();
GUIFactory factory = os.contains("mac") ? new MacFactory() : new WindowsFactory();
new Application(factory).renderUI();
}
}
| 維度 | 簡單工廠 | 工廠方法 | 抽象工廠 |
|---|---|---|---|
| 創建責任 | 集中在一個類 | 分散到多個子類 | 分散到多個工廠實現 |
| 產品結構 | 單一產品等級 | 單一產品等級 | 多產品族 (多等級) |
| 擴展新產品 | 修改工廠類 (違反 OCP) | 新增工廠子類 (符合 OCP) | 新增工廠實現+全族產品 |
| 擴展新產品族 | 不支持 | 不支持 | 新增工廠實現 (符合 OCP) |
| 客戶端依賴 | 具體工廠類 | 抽象工廠接口 | 抽象工廠接口 |
| 典型場景 | 工具類、參數化創建、產品固定少 | 框架擴展點、插件系統、單產品多實現 | 跨平台、多主題、多數據源適配器 |
| 複雜度 | 低 | 中 | 高 |
new Circle(p[0]));
REGISTRY.put("rectangle", p -> new Rectangle(p[0], p[1]));
}
public static Shape create(String type, double... params) {
return REGISTRY.getOrDefault(type, p -> { throw new IllegalArgumentException(); }).apply(params);
}
// 支持運行時動態註冊:REGISTRY.put("triangle", p -> new Triangle(...));
}
// META-INF/services/com.example.ShapeFactory
# 實現類全限定名
com.example.CircleFactory
com.example.RectangleFactory
// 運行時發現所有實現
ServiceLoader<ShapeFactory> loader = ServiceLoader.load(ShapeFactory.class);
for (ShapeFactory f : loader) {
// 自動發現第三方 JAR 提供的工廠
}
@Configuration
public class FactoryConfig {
@Bean @ConditionalOnProperty(name = "shape.type", havingValue = "circle")
public ShapeFactory circleFactory() { return new CircleFactory(); }
@Bean @ConditionalOnProperty(name = "shape.type", havingValue = "rectangle")
public ShapeFactory rectangleFactory() { return new RectangleFactory(); }
}
工廠模式三層進化本質是創建邏輯封裝層級的提升:簡單工廠封裝「判斷邏輯」,工廠方法封裝「創建類決策」,抽象工廠封裝「產品族一致性」。實戰中遵循「簡單優先、按需演進、接口隔離、註冊表替代繼承」原則,配合現代 Java 函數式特性與 SPI 機制,能構建出既靈活又可維護的對象創建體系。