工厂模式是一种创建型设计模式,其核心思想是定义一个创建对象的接口(即工厂),让子类决定实例化哪一个类。工厂模式将对象的创建与使用分离,使代码更易于维护和扩展,尤其在需要根据条件动态创建不同类的实例时非常有用。
工厂模式主要有以下三种形态:
简单工厂模式(Simple Factory)
工厂方法模式(Factory Method)
抽象工厂模式(Abstract Factory)
1、简单工厂模式(Simple Factory)
- 概念:定义一个工厂类,负责创建某一类对象,客户端通过调用工厂类的静态方法来获取所需对象。简单工厂模式封装了对象的创建过程,隐藏了具体产品的类名,使得客户只需关注产品的接口而非创建细节。
- 优点:减少客户端与具体产品类之间的耦合,新增产品时只需修改工厂类即可。
- 缺点:当产品种类较多时,工厂类可能会变得庞大且难以维护;违背开闭原则,增加新产品时需要修改工厂类代码。
Java代码示例:
// 定义产品接口
public interface Product {
void use();
}
// 具体产品A
public class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("Using product A");
}
}
// 具体产品B
public class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("Using product B");
}
}
// 工厂类
public class SimpleFactory {
public static Product createProduct(String type) {
if ("A".equals(type)) {
return new ConcreteProductA();
} else if ("B".equals(type)) {
return new ConcreteProductB();
} else {
throw new IllegalArgumentException("Invalid product type");
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Product productA = SimpleFactory.createProduct("A");
productA.use(); // 输出:Using product A
Product productB = SimpleFactory.createProduct("B");
productB.use(); // 输出:Using product B
}
}
2、工厂方法模式(Factory Method)
- 概念:定义一个用于创建对象的抽象工厂接口(或抽象类),并让子类决定实例化哪一个产品类。工厂方法模式将简单工厂的静态方法改为抽象方法,让子类去实现具体的对象创建。
- 优点:符合开闭原则,新增产品时只需增加新的工厂子类,无需修改原有代码;支持多态,子类可以覆盖基类的方法以提供不同类型的对象。
- 缺点:类的层级结构可能会变得复杂,特别是产品类型较多时。
Java代码示例:
// 定义产品接口
public interface Product {
void use();
}
// 具体产品A
public class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("Using product A");
}
}
// 具体产品B
public class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("Using product B");
}
}
// 抽象工厂接口
public interface Factory {
Product createProduct();
}
// 具体工厂A
public class ConcreteFactoryA implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// 具体工厂B
public class ConcreteFactoryB implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Factory factoryA = new ConcreteFactoryA();
Product productA = factoryA.createProduct();
productA.use(); // 输出:Using product A
Factory factoryB = new ConcreteFactoryB();
Product productB = factoryB.createProduct();
productB.use(); // 输出:Using product B
}
}
3、抽象工厂模式(Abstract Factory)
- 概念:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式为创建一组产品族提供了一个接口,而具体的产品族创建由具体工厂子类实现。
- 优点:隔离了具体产品类的使用,使得客户端只需与抽象产品和抽象工厂交互;支持产品族的切换,只需改变具体工厂的实例即可。
- 缺点:增加了系统的复杂性,尤其是产品族中产品类数量较多时;新增产品族时需要修改抽象工厂接口及其实现类。
Java代码示例:
// 定义产品接口
public interface ProductA {
void useA();
}
public interface ProductB {
void useB();
}
// 具体产品A1
public class ConcreteProductA1 implements ProductA {
@Override
public void useA() {
System.out.println("Using product A1");
}
}
// 具体产品B1
public class ConcreteProductB1 implements ProductB {
@Override
public void useB() {
System.out.println("Using product B1");
}
}
// 具体产品A2
public class ConcreteProductA2 implements ProductA {
@Override
public void useA() {
System.out.println("Using product A2");
}
}
// 具体产品B2
public class ConcreteProductB2 implements ProductB {
@Override
public void useB() {
System.out.println("Using product B2");
}
}
// 抽象工厂接口
public interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 具体工厂1
public class ConcreteFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂2
public class ConcreteFactory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
AbstractFactory factory1 = new ConcreteFactory1();
ProductA productA1 = factory1.createProductA();
productA1.useA(); // 输出:Using product A1
ProductB productB1 = factory1.createProductB();
productB1.useB(); // 输出:Using product B1
AbstractFactory factory2 = new ConcreteFactory2();
ProductA productA2 = factory2.createProductA();
productA2.useA(); // 输出:Using product A2
ProductB productB2 = factory2.createProductB();
productB2.useB(); // 输出:Using product B2
}
}
使用中需要注意的问题:
明确工厂职责:
- 确保工厂类或方法专注于对象创建,避免承担过多业务逻辑,保持其单一职责。如果工厂过于复杂,可能需要进一步抽象或拆分为多个工厂。
- 对于工厂方法模式和抽象工厂模式,要清晰划分工厂接口与具体工厂类的责任,确保接口的通用性和具体工厂类的可扩展性。
遵守开闭原则:
- 工厂模式的设计应遵循开闭原则,即对扩展开放,对修改关闭。新增产品时,应通过增加新的工厂类(工厂方法模式)或新的具体工厂子类(抽象工厂模式),而不是修改已有工厂类的代码。
- 对于简单工厂模式,虽然直接修改工厂类会导致违反开闭原则,但在简单场景下,或者产品种类较少、不易变动时,仍不失为一种实用的选择。如果预计产品种类会频繁增加或变动,建议使用工厂方法或抽象工厂模式。
处理依赖关系:
- 如果产品类之间存在复杂的依赖关系,或者需要一起创建一组相关对象,应考虑使用抽象工厂模式,它能更好地管理产品族的创建。
- 对于简单工厂或工厂方法模式,如果产品类的依赖关系比较简单,可以直接在工厂中创建或注入依赖。如果依赖关系较复杂,可能需要配合依赖注入框架或服务定位器模式来管理。
控制类的个数:
- 工厂模式可能会增加类的数量,特别是在产品种类较多时。应合理规划类结构,避免类爆炸。可以通过模块化、分包等方式组织代码,提高可读性和可维护性。
- 对于简单工厂模式,如果产品种类过多导致工厂类庞大,可以考虑使用策略模式或枚举类等方式替代部分简单工厂功能。
考虑使用场景:
- 工厂模式并非所有情况下的首选解决方案。对于简单对象的创建,直接使用构造函数或静态工厂方法可能更为简洁。只有在对象创建逻辑复杂、需要动态决定创建何种对象,或者希望将对象创建细节与使用分离时,才应考虑使用工厂模式。
测试与调试:
- 工厂模式可能会增加代码的复杂性,影响测试的便利性。应确保工厂类及其创建的产品类具有良好的可测试性,如提供适当的构造函数、依赖注入点或模拟接口,以便于单元测试。
- 调试时,注意跟踪工厂创建对象的过程,特别是涉及多层工厂或工厂链时,确保对象的创建路径符合预期。
代码复用与扩展:
- 如果多个工厂有相似的创建逻辑,可以考虑提取公共部分到基类或工具类中,避免代码重复。
- 在设计工厂接口时,要考虑未来的扩展性,确保接口定义能够适应潜在的新产品类型。
性能与资源管理:
- 如果工厂模式用于创建资源密集型对象(如数据库连接、文件句柄等),需要考虑资源的有效管理和回收,避免资源泄露。
- 对于工厂方法模式,如果工厂类实例化成本较高,可以考虑使用单例模式或享元模式来优化。
总结来说,使用工厂模式时,应关注职责划分、开闭原则的遵循、依赖关系管理、类数量控制、使用场景选择、测试与调试的便利性、代码复用与扩展性以及性能与资源管理等方面的问题,以确保模式的有效运用和系统的健壮性。