工厂模式作为创建型设计模式的代表,其核心价值在于解耦对象的创建与使用。想象一下你去餐厅点餐的场景:作为顾客,你只需要告诉服务员"我要一份牛排",而不需要关心牛排是如何烹饪的、由哪位厨师制作的。工厂模式正是扮演着这个"服务员"的角色,让客户端代码无需知晓对象创建的具体细节。
在Java生态中,工厂模式的应用无处不在。从Spring框架的BeanFactory到JDK中的Collection工厂方法,再到各种开源库的对象创建逻辑,工厂模式都发挥着重要作用。它特别适合以下场景:
简单工厂模式的核心在于一个集中化的工厂类,它根据输入参数决定创建哪种具体产品。让我们扩展计算器案例,看看更完整的实现:
java复制// 产品接口
public interface Operation {
double calculate(double a, double b);
}
// 具体产品类
public class Addition implements Operation {
@Override
public double calculate(double a, double b) {
return a + b;
}
}
public class Subtraction implements Operation {
@Override
public double calculate(double a, double b) {
return a - b;
}
}
// 工厂类
public class OperationFactory {
public static Operation createOperation(String operator) {
switch (operator) {
case "+": return new Addition();
case "-": return new Subtraction();
case "*": return new Multiplication(); // 扩展乘法
case "/": return new Division(); // 扩展除法
default: throw new IllegalArgumentException("未知运算符");
}
}
}
关键设计要点:工厂类通常使用静态方法,这样客户端可以直接通过类名调用,无需实例化工厂对象。但这也带来了难以扩展的问题。
简单工厂模式特别适合以下场景:
典型案例包括:
优势体现:
局限性:
经验之谈:当发现工厂类的switch/case或if-else超过20行时,就应该考虑升级为工厂方法模式了。
工厂方法模式将对象的创建延迟到子类,定义了一个创建对象的接口,但让子类决定实例化哪个类。我们扩展计算器案例:
java复制// 抽象工厂
public interface OperationFactory {
Operation createOperation();
}
// 具体工厂
public class AddFactory implements OperationFactory {
@Override
public Operation createOperation() {
return new Addition();
}
}
public class SubFactory implements OperationFactory {
@Override
public Operation createOperation() {
return new Subtraction();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
OperationFactory factory = new AddFactory();
Operation op = factory.createOperation();
double result = op.calculate(5, 3);
}
}
工厂方法模式的核心优势在于符合开闭原则。当需要新增运算类型时:
这种扩展方式完全避免了修改现有代码,大大降低了引入bug的风险。在框架设计中,这种特性尤为重要,比如Spring的BeanFactory就是典型的工厂方法模式实现。
在复杂项目中应用工厂方法模式时,有几个实用技巧:
工厂接口设计:工厂方法可以接收参数,实现更灵活的创建逻辑
java复制public interface OperationFactory {
Operation createOperation(String config);
}
使用泛型:使工厂接口更加类型安全
java复制public interface Factory<T> {
T create();
}
组合使用其他模式:常与单例模式结合,确保工厂对象唯一
java复制public class AddFactory implements OperationFactory {
private static final AddFactory INSTANCE = new AddFactory();
private AddFactory() {}
public static AddFactory getInstance() {
return INSTANCE;
}
}
抽象工厂模式是工厂方法模式的升级版,它管理的是多个相关联的产品族。以GUI库为例:
java复制// 抽象产品接口
public interface Button {
void render();
}
public interface Checkbox {
void render();
}
// 抽象工厂
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// 具体工厂 - Windows风格
public class WinFactory implements GUIFactory {
public Button createButton() {
return new WinButton();
}
public Checkbox createCheckbox() {
return new WinCheckbox();
}
}
// 具体工厂 - Mac风格
public class MacFactory implements GUIFactory {
public Button createButton() {
return new MacButton();
}
public Checkbox createCheckbox() {
return new MacCheckbox();
}
}
抽象工厂特别适合以下复杂场景:
典型应用包括:
在实际项目中,抽象工厂常与其他模式组合使用:
与原型模式结合:通过克隆预定义的原型对象来提高性能
java复制public class PrototypeFactory implements GUIFactory {
private Button buttonPrototype;
private Checkbox checkboxPrototype;
public PrototypeFactory(Button b, Checkbox c) {
this.buttonPrototype = b;
this.checkboxPrototype = c;
}
public Button createButton() {
return buttonPrototype.clone();
}
}
使用依赖注入:通过Spring等框架管理工厂实例
java复制@Configuration
public class AppConfig {
@Bean
@ConditionalOnProperty(name="ui.style", havingValue="mac")
public GUIFactory macFactory() {
return new MacFactory();
}
}
缓存机制:对创建成本高的对象实施缓存
java复制public class CachedFactory implements GUIFactory {
private Map<String, Button> buttonCache = new ConcurrentHashMap<>();
public Button createButton(String style) {
return buttonCache.computeIfAbsent(style,
k -> new HeavyButton(k));
}
}
| 特性 | 简单工厂模式 | 工厂方法模式 | 抽象工厂模式 |
|---|---|---|---|
| 复杂度 | 低 | 中 | 高 |
| 开闭原则 | 违反 | 支持 | 支持 |
| 产品维度 | 单一产品 | 单一产品 | 产品族 |
| 扩展性 | 修改工厂类 | 新增工厂子类 | 新增工厂子类 |
| 适用场景 | 简单对象创建 | 单一产品系列 | 复杂产品家族 |
| 类数量增长 | 线性增长 | 产品类×2 | 产品族×产品类型 |
是否需要创建多个相关联的产品?
产品类型是否会频繁扩展?
对象创建逻辑是否简单?
在实际应用中,还需要考虑以下性能因素:
最佳实践建议:
Spring的BeanFactory是工厂模式的经典实现:
java复制public interface BeanFactory {
Object getBean(String name);
<T> T getBean(Class<T> requiredType);
<T> T getBean(String name, Class<T> requiredType);
}
Spring通过这种设计实现了:
Java标准库中也大量使用工厂模式:
java复制List<String> list = Collections.unmodifiableList(originalList);
java复制Charset charset = Charset.forName("UTF-8");
java复制DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
在项目中集成工厂模式时,建议:
当产品A依赖产品B,而产品B又依赖产品A时,简单工厂可能导致栈溢出:
java复制public class ProductA {
private ProductB b = Factory.createB();
}
public class ProductB {
private ProductA a = Factory.createA();
}
解决方案:
当需要运行时动态添加新产品类型时,传统工厂模式可能受限:
java复制// 需要支持插件式新增运算类型
public void registerOperation(String symbol, Operation op) {
// 如何扩展?
}
解决方案:
测试工厂类时的关键点:
示例测试用例:
java复制@Test
public void testCreateAddition() {
Operation op = OperationFactory.createOperation("+");
assertTrue(op instanceof Addition);
assertEquals(5, op.calculate(2, 3), 0.001);
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidOperator() {
OperationFactory.createOperation("$");
}
将工厂模式与策略模式结合,可以创建更灵活的系统:
java复制// 策略接口
public interface DiscountStrategy {
double applyDiscount(double amount);
}
// 策略工厂
public class DiscountStrategyFactory {
public DiscountStrategy getStrategy(Customer customer) {
if (customer.isVIP()) {
return new VIPDiscount();
} else if (customer.isNew()) {
return new NewCustomerDiscount();
} else {
return new RegularDiscount();
}
}
}
// 使用示例
public class OrderService {
private DiscountStrategyFactory factory;
public double calculateFinalPrice(Order order, Customer customer) {
DiscountStrategy strategy = factory.getStrategy(customer);
return strategy.applyDiscount(order.getTotal());
}
}
通过工厂创建装饰后的对象:
java复制public interface DataService {
String fetchData();
}
public class BasicDataService implements DataService {
public String fetchData() {
return "raw data";
}
}
public class DataServiceFactory {
public DataService createService(boolean encrypted, boolean compressed) {
DataService service = new BasicDataService();
if (encrypted) {
service = new EncryptionDecorator(service);
}
if (compressed) {
service = new CompressionDecorator(service);
}
return service;
}
}
对于复杂对象的创建,可以结合生成器模式:
java复制public class Report {
private Header header;
private Body body;
private Footer footer;
// 构造器私有,只能通过生成器创建
private Report(Builder builder) {
this.header = builder.header;
this.body = builder.body;
this.footer = builder.footer;
}
public static class Builder {
private Header header;
private Body body;
private Footer footer;
public Builder withHeader(Header header) {
this.header = header;
return this;
}
// 其他构建方法...
public Report build() {
return new Report(this);
}
}
}
public class ReportFactory {
public Report createMonthlyReport() {
return new Report.Builder()
.withHeader(new MonthlyHeader())
.withBody(new MonthlyBody())
.withFooter(new StandardFooter())
.build();
}
}
Java 8之后,可以用函数式接口简化工厂实现:
java复制public enum OperationFactory {
ADD((a, b) -> a + b),
SUB((a, b) -> a - b),
MUL((a, b) -> a * b);
private final DoubleBinaryOperator operation;
OperationFactory(DoubleBinaryOperator operation) {
this.operation = operation;
}
public double apply(double a, double b) {
return operation.applyAsDouble(a, b);
}
}
// 使用
double result = OperationFactory.ADD.apply(2.5, 3.5);
Java 9模块系统(JPMS)下,工厂模式的新写法:
java复制module com.example.factory {
exports com.example.factory.api;
provides com.example.factory.api.ServiceFactory
with com.example.factory.impl.DefaultServiceFactory;
}
Java 14引入的Record类型可以与工厂模式很好结合:
java复制public record Point(int x, int y) {
// 工厂方法
public static Point origin() {
return new Point(0, 0);
}
public static Point fromPolar(double radius, double angle) {
return new Point(
(int)(radius * Math.cos(angle)),
(int)(radius * Math.sin(angle))
);
}
}
对于频繁创建的对象,实施缓存可以显著提升性能:
java复制public class CachedFactory {
private static final Map<String, Operation> cache = new ConcurrentHashMap<>();
public Operation getOperation(String type) {
return cache.computeIfAbsent(type, t -> {
switch (t) {
case "+": return new Addition();
case "-": return new Subtraction();
default: throw new IllegalArgumentException();
}
});
}
}
全能工厂:一个工厂类创建完全不相关的产品
java复制// 反例:一个工厂创建数据库连接、UI组件和业务对象
public class GodFactory {
public Object create(String type) {
// 各种不相关的创建逻辑
}
}
过度抽象:为简单对象创建复杂工厂层次
java复制// 反例:为只有一种实现的接口创建工厂
public interface SimpleServiceFactory {
SimpleService create();
}
隐藏依赖:工厂方法掩盖了对象间的真实依赖关系
java复制// 反例:在业务逻辑中直接调用静态工厂
public class OrderProcessor {
public void process() {
Logger logger = LoggerFactory.create();
// 处理逻辑
}
}
在多线程环境中使用工厂模式时需要注意:
无状态工厂:最佳实践是保持工厂无状态
java复制public class ThreadSafeFactory {
// 无实例字段,只有静态工厂方法
public static Product create() {
return new ProductImpl();
}
}
有状态工厂:需要适当同步
java复制public class StatefulFactory {
private int count;
private final Object lock = new Object();
public Product create() {
synchronized(lock) {
count++;
return new ProductImpl(count);
}
}
}
双重检查锁定:对昂贵对象的懒加载
java复制public class SingletonFactory {
private volatile Product instance;
public Product getInstance() {
if (instance == null) {
synchronized(this) {
if (instance == null) {
instance = createExpensiveProduct();
}
}
}
return instance;
}
}
工厂模式作为对象创建的瑞士军刀,其价值在于提供了一种灵活、可扩展的对象创建方案。在实际项目中,我倾向于从简单工厂开始,随着需求复杂度的增加逐步升级到工厂方法或抽象工厂。记住,没有最好的模式,只有最适合当前场景的模式。关键是要理解每种变体的优缺点,并在代码可维护性和灵活性之间找到平衡点。